Trait Ordination Plant Community Analysis

  1. traits

    1. above- and belowground

      1. height & SLA
    2. acquisitive vs. conservative resource-use strategies

      1. rooting depth
    3. collaborative vs. individual resource-use strategies

      1. fine root proportion

      2. thickness of roots

Goal: Examine how traits shift in community compositional (ordinational) space, placing each trait on an axis.

Author: Caryn D. Iwanaga

Updated: 02/06/2025

Libraries

library(tidyverse)
library(dplyr)
library(ggplot2)
library(httr) # read out Dropbox folders
library(vegan)
library(readxl)

Read in Data

cover.dat.labels <- read.csv("https://www.dropbox.com/scl/fi/up8nnzkcpchsr45f8cm92/Compost_Cover_LongClean.csv?rlkey=z2tvaj8t6khadef7ydz782zka&st=qwef9ys0&dl=1") %>%
  mutate(
    nut_trt = factor(ifelse(nut_trt =="C", "+compost", ifelse(nut_trt =="F", "+N fertilizer", ifelse(nut_trt =="N", "control", NA))), levels = c("control", "+N fertilizer", "+compost")),
    ppt_trt = ifelse(ppt_trt == "D", "dry", ifelse(ppt_trt == "XC", "control", ifelse(ppt_trt == "W", "wet", NA))))


# Define a reusable color scale
# custom_colors <- scale_fill_manual(
#   values = c(
#     "control" = rgb(195, 197, 193, maxColorValue = 250),
#     "+N fertilizer" = rgb(87, 62, 92, maxColorValue = 225),
#     "+compost" = rgb(167, 156, 109, maxColorValue = 225)
#   )
# )

custom_colors <- scale_fill_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

# Set a global theme
theme_set(theme_bw())

Make site x species matrix

  1. Calculate relative abundances of species for each site
    1. confused how to aggregate abundances because even grouping by plotid (nut_trt and ppt_trt), year, species, and grazing history (block 1&2 – high, block 3&4 – low) and averaged, the sd are as high as 45.96!
      1. proceeded with these high sd to see what happens (ask Lauren)
    2. try how it is when you split everything by each block (more representative?)
site.df <- 
  cover.dat.labels[, c(1:7, 18:19)] %>% #subset columns
  mutate(
    grazing_hist = ifelse(block == 1 | block == 2, "high", ifelse(block == 3 | block == 4, "low", NA))
  ) %>% # separate by block (grazing intensities)
  group_by(nut_trt, ppt_trt, yr, code4, grazing_hist) %>% # make each code unique -- one value for species abundance for each trt
  summarise(
    # pct_cover,
    abundance = mean(pct_cover)
    # sd = sd(pct_cover)
  )
`summarise()` has grouped output by 'nut_trt', 'ppt_trt', 'yr', 'code4'. You can override using the `.groups` argument.
matrix0 <- spread(
  site.df, 
  code4, 
  abundance, 
  fill = 0)

# make rownames ----
rownames(matrix0) <- paste(matrix0$nut_trt, matrix0$ppt_trt, matrix0$yr, matrix0$grazing_hist, sep = "_")
Warning: Setting row names on a tibble is deprecated.
# delete columns ---- 
matrix <- matrix0[, c(5:79)]

# relativize data with Bray-Curtis dissimilarity
matrix.bray <- decostand(matrix, "total")
rownames(matrix.bray) <- rownames(matrix0)

Split matrix by each block as well

site.block.df <- 
  cover.dat.labels[, c(1:7, 18:19)] %>% #subset columns
  group_by(nut_trt, ppt_trt, yr, code4, block) %>% # make each code unique -- one value for species abundance for each trt
  summarise(
    # pct_cover,
    abundance = mean(pct_cover)
    # sd = sd(pct_cover)
  )
`summarise()` has grouped output by 'nut_trt', 'ppt_trt', 'yr', 'code4'. You can override using the `.groups` argument.
site.block.sd.df <- 
  cover.dat.labels[, c(1:7, 18:19)] %>% #subset columns
  group_by(nut_trt, ppt_trt, yr, code4, block) %>% # make each code unique -- one value for species abundance for each trt
  summarise(
    pct_cover,
    abundance = mean(pct_cover),
    sd = sd(pct_cover)
  )
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.`summarise()` has grouped output by 'nut_trt', 'ppt_trt', 'yr', 'code4', 'block'. You can override using the `.groups` argument.
matrix0.block <- spread(
  site.block.df, 
  code4, 
  abundance, 
  fill = 0)

# make rownames ----
rownames(matrix0.block) <- paste(matrix0.block$nut_trt, matrix0.block$ppt_trt, matrix0.block$yr, matrix0.block$block, sep = "_")
Warning: Setting row names on a tibble is deprecated.
# delete columns ---- 
matrix.block <- matrix0.block[, -c(0:4)]

# relativize data with Bray-Curtis dissimilarity
matrix.block.bray <- decostand(matrix.block, "total")
rownames(matrix.block.bray) <- rownames(matrix0.block)

Run NMDS

Rules of thumb:

  • < 0.05 is excellent

  • 0.05-0.1 is good

  • 0.1-0.2 is fair

  • 0.2-0.3 is cause for concern…

  • > 0.3 is poor, random

All years – low & high grazing

Stress: fair

0.1966553 

Grouping by year and grazing history had most significant clustering shown.

metaMDS()
nmds.comp <- metaMDS(matrix.bray, k=2, trymax = 25)
Run 0 stress 0.2020736 
Run 1 stress 0.2044105 
Run 2 stress 0.2084765 
Run 3 stress 0.2084764 
Run 4 stress 0.2026778 
Run 5 stress 0.2018338 
... New best solution
... Procrustes: rmse 0.06193884  max resid 0.2323138 
Run 6 stress 0.1971149 
... New best solution
... Procrustes: rmse 0.02534655  max resid 0.1298511 
Run 7 stress 0.2027879 
Run 8 stress 0.20163 
Run 9 stress 0.2033608 
Run 10 stress 0.2017485 
Run 11 stress 0.2176904 
Run 12 stress 0.2013629 
Run 13 stress 0.1966668 
... New best solution
... Procrustes: rmse 0.01514645  max resid 0.1046137 
Run 14 stress 0.1991103 
Run 15 stress 0.202025 
Run 16 stress 0.2033208 
Run 17 stress 0.2020741 
Run 18 stress 0.2034839 
Run 19 stress 0.2043941 
Run 20 stress 0.1991947 
Run 21 stress 0.2128964 
Run 22 stress 0.1991946 
Run 23 stress 0.2039391 
Run 24 stress 0.2133823 
Run 25 stress 0.196656 
... New best solution
... Procrustes: rmse 0.004511995  max resid 0.02760931 
*** Best solution was not repeated -- monoMDS stopping criteria:
    24: stress ratio > sratmax
     1: scale factor of the gradient < sfgrmin
nmds.comp # pretty not great stress

Call:
metaMDS(comm = matrix.bray, k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray 
Distance: bray 

Dimensions: 2 
Stress:     0.196656 
Stress type 1, weak ties
Best solution was not repeated after 25 tries
The best solution was from try 25 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray’ 
stressplot(nmds.comp)

plot(nmds.comp, type="t")


nmds1 <- as.data.frame(scores(nmds.comp, choices=c(1), display=c("sites"))) %>%
  mutate(matrix0[, c(0:4)])
nmds2 <- as.data.frame(scores(nmds.comp, choices=c(2), display=c("sites")))

nmds_dat <- cbind(nmds1, nmds2) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
ggplot(nmds_dat, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Nutrient Treatment") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.

ggplot(nmds_dat, aes(NMDS1, NMDS2, color = as.factor(yr), fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Year")


ggplot(nmds_dat, aes(NMDS1, NMDS2, fill = as.factor(ppt_trt), color = as.factor(ppt_trt))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Precipitation Treatment") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)


ggplot(nmds_dat, aes(NMDS1, NMDS2,  fill = as.factor(grazing_hist), color = as.factor(grazing_hist))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Grazing History")


ggplot(nmds_dat, aes(NMDS1, NMDS2,  color = as.factor(grazing_hist), fill = as.factor(yr))) +
  geom_point(aes(fill = as.factor(yr)), shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(yr)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  labs(title = "Grouped by Grazing History & Year") +
  scale_color_manual(
  values = c(
    "low" = "cyan",
    "high" = "brown",
  "2019" = "salmon",
  "2020" = "limegreen",
  "2021" = "cornflowerblue")
  )

  
ggplot(nmds_dat, aes(NMDS1, NMDS2, color = nut_trt, fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(nut_trt)),
             geom = "polygon",
             fill = NA,  # Makes the ellipse transparent inside
             size = 1) +
  labs(title = "Grouped by Nutrient Treatment & Year") +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

All years – blocks

Stress: cause for concern

0.2329306
metaMDS()
nmds.block.comp <- metaMDS(matrix.block.bray, k=2, trymax = 25)
nmds.block.comp
stressplot(nmds.block.comp)
plot(nmds.block.comp, type="t")

nmds1 <- as.data.frame(scores(nmds.block.comp, choices=c(1), display=c("sites"))) %>%
  mutate(matrix0.block[, c(0:4)])
nmds2 <- as.data.frame(scores(nmds.block.comp, choices=c(2), display=c("sites")))

nmds_dat.block <- cbind(nmds1, nmds2) %>%
  select(nut_trt:block, NMDS1, NMDS2)
plot
ggplot(nmds_dat.block, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Nutrient Treatment - Blocks") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

ggplot(nmds_dat.block, aes(NMDS1, NMDS2, color = as.factor(yr), fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Year - Blocks")

ggplot(nmds_dat.block, aes(NMDS1, NMDS2, fill = as.factor(ppt_trt), color = as.factor(ppt_trt))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Precipitation Treatment - Blocks") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

ggplot(nmds_dat.block, aes(NMDS1, NMDS2,  fill = as.factor(block), color = as.factor(block))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Block")

ggplot(nmds_dat.block, aes(NMDS1, NMDS2,  color = as.factor(block), fill = as.factor(yr))) +
  geom_point(aes(fill = as.factor(yr)), shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(block)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  labs(title = "Grouped by Block & Year - Blocks") +
  scale_color_manual(
  values = c(
    # "low" = "cyan",
    # "high" = "brown",
  "2019" = "salmon",
  "2020" = "limegreen",
  "2021" = "cornflowerblue")
  )
  
ggplot(nmds_dat.block, aes(NMDS1, NMDS2, color = nut_trt, fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(nut_trt)),
             geom = "polygon",
             fill = NA,  # Makes the ellipse transparent inside
             size = 1) +
  labs(title = "Grouped by Nutrient Treatment & Year - Blocks") +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

All years - LOW GRAZING ONLY

Stress: fair

0.1869068

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.low <- matrix0 %>%
  filter(grazing_hist == "low")

row.low <- paste(matrix.low$nut_trt, matrix.low$ppt_trt, matrix.low$yr, matrix.low$grazing_hist, sep = "_")

matrix.low <- matrix.low[, c(5:79)]

rownames(matrix.low) <- row.low

matrix.bray.low <- decostand(matrix.low, "total")

metaMDS()

nmds.comp.low <- metaMDS(matrix.bray.low, k=2, trymax = 25)
nmds.comp.low # pretty not great stress
stressplot(nmds.comp.low)
plot(nmds.comp.low, type="t")

nmds1 <- as.data.frame(scores(nmds.comp.low, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.low), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.low), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.low), "_"), `[`, 3),
    grazing_hist = sapply(strsplit(rownames(matrix.low), "_"), `[`, 4)
  )
nmds2 <- as.data.frame(scores(nmds.comp.low, choices=c(2), display=c("sites")))

nmds_low_dat <- cbind(nmds1, nmds2) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)

plot

ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  color = as.factor(yr), shape = nut_trt)) +
  geom_point(size = 3, stroke = 1) + 
  labs(title = "2019-2021 (LOW) - Grouping by Year & Nutrient Treatment")

ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  labs(title = "2019-2021 (LOW) - Grouping by Nutrient Treatment")+ 
  custom_colors


ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2019-2021 (LOW) - Grouping by Precipitation Treatment") 

# add year ellipses ---- 
ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(aes(color = as.factor(yr)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  labs(title = "2019-2021 (LOW) - Grouping by Nutrient Treatment")+ 
  custom_colors


ggplot(nmds_low_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
    stat_ellipse(aes(color = as.factor(yr)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  custom_colors + 
  labs(title = "2019-2021 (LOW) - Grouping by Precipitation Treatment") 

Make each individual year NMDS to see if there’s better stress

2019

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2019 <- matrix0 %>%
  filter(yr == 2019)

row.2019 <- paste(matrix.2019$nut_trt, matrix.2019$ppt_trt, matrix.2019$yr, matrix.2019$grazing_hist, sep = "_")

matrix.2019 <- matrix.2019[, c(5:79)]

rownames(matrix.2019) <- row.2019

matrix.bray.2019 <- decostand(matrix.2019, "total")

nmds 2019

Stress: Excellent

0.0560178
metaMDS()
nmds.2019 <- metaMDS(matrix.bray.2019, k=2, trymax = 25)
nmds.2019 # pretty not great stress
stressplot(nmds.2019)
plot(nmds.2019, type="t")

nmds1.2019 <- as.data.frame(scores(nmds.2019, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 3),
    grazing_hist = sapply(strsplit(rownames(matrix.2019), "_"), `[`, 4)
  )
nmds2.2019 <- as.data.frame(scores(nmds.2019, choices=c(2), display=c("sites")))

nmds_2019_dat <- cbind(nmds1.2019, nmds2.2019) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
ggplot(nmds_2019_dat, aes(NMDS1, NMDS2,  color = grazing_hist, shape = nut_trt)) +
  geom_point(size = 3, stroke = 1) + 
  labs(title = "2019 - Grouping by Grazing History & Nutrient Treatment")

ggplot(nmds_2019_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  labs(title = "2019 - Grouping by Nutrient Treatment")+ 
  custom_colors


ggplot(nmds_2019_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2019 - Grouping by Precipitation Treatment") 

2020

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2020 <- matrix0 %>%
  filter(yr == 2020)

row.2020 <- paste(matrix.2020$nut_trt, matrix.2020$ppt_trt, matrix.2020$yr, matrix.2020$grazing_hist, sep = "_")

matrix.2020 <- matrix.2020[, c(5:79)]

rownames(matrix.2020) <- row.2020

matrix.bray.2020 <- decostand(matrix.2020, "total")

nmds 2020

Stress: fair

0.1522495
metaMDS()
nmds.2020 <- metaMDS(matrix.bray.2020, k=2, trymax = 25)
nmds.2020
stressplot(nmds.2020)
plot(nmds.2020, type="t")

nmds1.2020 <- as.data.frame(scores(nmds.2020, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 3),
    grazing_hist = sapply(strsplit(rownames(matrix.2020), "_"), `[`, 4)
  )
nmds2.2020 <- as.data.frame(scores(nmds.2020, choices=c(2), display=c("sites")))

nmds_2020_dat <- cbind(nmds1.2020, nmds2.2020) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
ggplot(nmds_2020_dat, aes(NMDS1, NMDS2,  color = grazing_hist, shape = nut_trt)) +
  geom_point(size = 4, stroke = 1) + 
  labs(title = "2020 - Grouping by Grazing History & Nutrient Treatment") 

ggplot(nmds_2020_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2020 - Grouping by Nutrient Treatment")

ggplot(nmds_2020_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2020 - Grouping by Precipitation Treatment")

2021

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2021 <- matrix0 %>%
  filter(yr == 2021)

row.2021 <- paste(matrix.2021$nut_trt, matrix.2021$ppt_trt, matrix.2021$yr, matrix.2021$grazing_hist, sep = "_")

matrix.2021 <- matrix.2021[, c(5:79)]

rownames(matrix.2021) <- row.2021

matrix.bray.2021 <- decostand(matrix.2021, "total")
2021 - LOW

Stress

0.08067789
# relativize data with Bray-Curtis dissimilarity
matrix.2021.1 <- matrix0 %>%
  filter(yr == 2021,
         grazing_hist == "low") 

row.2021.1 <- paste(matrix.2021.1$nut_trt, matrix.2021.1$ppt_trt, matrix.2021.1$yr, matrix.2021.1$grazing_hist, sep = "_")

matrix.2021.1 <- matrix.2021.1[, c(5:79)]

rownames(matrix.2021.1) <- row.2021.1

matrix.bray.2021.1 <- decostand(matrix.2021.1, "total")
nmds.2021.1 <- metaMDS(matrix.bray.2021.1, k=2, trymax = 25)
nmds.2021.1
stressplot(nmds.2021.1)
plot(nmds.2021.1, type="t")
dummy <- as.data.frame(scores(nmds.2021.1, choices=c(1), display=c("sites")))

nmds1.2021.1.df <- as.data.frame(scores(nmds.2021.1, choices=c(1), display=c("sites"))) %>%
  mutate(trt = rownames(dummy)) %>%
  separate(trt, c("nut_trt", "ppt_trt", "pr", "grazing_hist"), sep="_")

nmds2.2021.1 <- as.data.frame(scores(nmds.2021.1, choices=c(2), display=c("sites")))

nmds_2021_dat.1 <- cbind(nmds1.2021.1.df, nmds2.2021.1) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
# ggplot(nmds_2021_dat.1, aes(NMDS1, NMDS2,  color = grazing_hist, shape = nut_trt)) +
#   geom_point(size = 4, stroke = 0.5) +
#   labs(title = "2021 - Grouping by Grazing History & Nutrient Treatment")

ggplot(nmds_2021_dat.1, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (LOW) - Grouping by Nutrient Treatment")

ggplot(nmds_2021_dat.1, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (LOW) - Grouping by Precipitation Treatment")
2021 - HIGH

Stress

0.08065034
# relativize data with Bray-Curtis dissimilarity
matrix.2021.2 <- matrix0 %>%
  filter(yr == 2021,
         grazing_hist == "high") 

row.2021.2 <- paste(matrix.2021.2$nut_trt, matrix.2021.2$ppt_trt, matrix.2021.2$yr, matrix.2021.2$grazing_hist, sep = "_")

matrix.2021.2 <- matrix.2021.2[, c(5:79)]

rownames(matrix.2021.2) <- row.2021.2

matrix.bray.2021.2 <- decostand(matrix.2021.2, "total")
nmds.2021.2 <- metaMDS(matrix.bray.2021.2, k=2, trymax = 25)
nmds.2021.2
stressplot(nmds.2021.2)
plot(nmds.2021.2, type="t")
dummy <- as.data.frame(scores(nmds.2021.2, choices=c(1), display=c("sites")))

nmds1.2021.2.df <- as.data.frame(scores(nmds.2021.2, choices=c(1), display=c("sites"))) %>%
  mutate(trt = rownames(dummy)) %>%
  separate(trt, c("nut_trt", "ppt_trt", "pr", "grazing_hist"), sep="_")

nmds2.2021.2 <- as.data.frame(scores(nmds.2021.2, choices=c(2), display=c("sites")))

nmds_2021_dat.2 <- cbind(nmds1.2021.2.df, nmds2.2021.2) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
ggplot(nmds_2021_dat.2, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (HIGH) - Grouping by Nutrient Treatment")

ggplot(nmds_2021_dat.2, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (HIGH) - Grouping by Precipitation Treatment")

nmds 2021

Stress: fair

0.1230831
metaMDS()
nmds.2021 <- metaMDS(matrix.bray.2021, k=2, trymax = 25)
nmds.2021
stressplot(nmds.2021)
plot(nmds.2021, type="t")

nmds1.2021 <- as.data.frame(scores(nmds.2021, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 3),
    grazing_hist = sapply(strsplit(rownames(matrix.2021), "_"), `[`, 4)
  )
nmds2.2021 <- as.data.frame(scores(nmds.2021, choices=c(2), display=c("sites")))

nmds_2021_dat <- cbind(nmds1.2021, nmds2.2021) %>%
  select(nut_trt:grazing_hist, NMDS1, NMDS2)
plot
ggplot(nmds_2021_dat, aes(NMDS1, NMDS2,  color = grazing_hist, shape = nut_trt)) +
  geom_point(size = 4, stroke = 0.5) +
  labs(title = "2021 - Grouping by Grazing History & Nutrient Treatment")

ggplot(nmds_2021_dat, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 - Grouping by Nutrient Treatment")

ggplot(nmds_2021_dat, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 - Grouping by Precipitation Treatment")

2021 — blocks

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2021.block <- matrix0.block %>%
  filter(yr == 2021)

row.2021.block <- paste(matrix.2021.block$nut_trt, matrix.2021.block$ppt_trt, matrix.2021.block$yr, matrix.2021.block$block, sep = "_")

matrix.2021.block <- matrix.2021.block[, c(5:79)]

rownames(matrix.2021.block) <- row.2021.block

matrix.bray.block.2021 <- decostand(matrix.2021.block, "total")

nmds 2021

Stress: fair

0.1702944
metaMDS()
nmds.2021.block <- metaMDS(matrix.bray.block.2021, k=2, trymax = 25)
nmds.2021.block
stressplot(nmds.2021.block)
plot(nmds.2021.block, type="t")

nmds1.2021.block <- as.data.frame(scores(nmds.2021.block, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2021.block), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2021.block), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2021.block), "_"), `[`, 3),
    block = sapply(strsplit(rownames(matrix.2021.block), "_"), `[`, 4)
  )
nmds2.2021.block <- as.data.frame(scores(nmds.2021.block, choices=c(2), display=c("sites")))

nmds_2021_dat.block <- cbind(nmds1.2021.block, nmds2.2021.block) %>%
  select(nut_trt:block, NMDS1, NMDS2)
plot
ggplot(nmds_2021_dat.block, aes(NMDS1, NMDS2,  color = block, shape = nut_trt)) +
  geom_point(size = 4, stroke = 0.5) +
  labs(title = "2021 (Block) - Grouping by Block & Nutrient Treatment")

ggplot(nmds_2021_dat.block, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block) - Grouping by Nutrient Treatment")

ggplot(nmds_2021_dat.block, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block) - Grouping by Precipitation Treatment")

2021 — blocks (LOW)

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2021.block.low <- matrix0.block %>%
  filter(yr == 2021,
         block == 3 | block == 4)

row.2021.block.low <- paste(matrix.2021.block.low$nut_trt, matrix.2021.block.low$ppt_trt, matrix.2021.block.low$yr, matrix.2021.block.low$block, sep = "_")

matrix.2021.block.low <- matrix.2021.block.low[, -c(0:4)]

rownames(matrix.2021.block.low) <- row.2021.block.low

matrix.bray.block.2021.low <- decostand(matrix.2021.block.low, "total")

nmds 2021

Stress: fair

0.1282296
metaMDS()
nmds.2021.block.low <- metaMDS(matrix.bray.block.2021.low, k=2, trymax = 25)
nmds.2021.block.low
stressplot(nmds.2021.block.low)
plot(nmds.2021.block.low, type="t")

nmds1.2021.block.low <- as.data.frame(scores(nmds.2021.block.low, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2021.block.low), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2021.block.low), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2021.block.low), "_"), `[`, 3),
    block = sapply(strsplit(rownames(matrix.2021.block.low), "_"), `[`, 4)
  )
nmds2.2021.block.low <- as.data.frame(scores(nmds.2021.block.low, choices=c(2), display=c("sites")))

nmds_2021_dat.block.low <- cbind(nmds1.2021.block.low, nmds2.2021.block.low) %>%
  select(nut_trt:block, NMDS1, NMDS2)
plot
ggplot(nmds_2021_dat.block.low, aes(NMDS1, NMDS2,  color = block, shape = nut_trt)) +
  geom_point(size = 4, stroke = 0.5) +
  labs(title = "2021 (Block; LOW) - Grouping by Block & Nutrient Treatment")

ggplot(nmds_2021_dat.block.low, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; LOW) - Grouping by Nutrient Treatment")

ggplot(nmds_2021_dat.block.low, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; LOW) - Grouping by Precipitation Treatment")

2021 — blocks (HIGH)

data wrangling

# relativize data with Bray-Curtis dissimilarity
matrix.2021.block.high <- matrix0.block %>%
  filter(yr == 2021,
         block == 1 | block == 2)

row.2021.block.high <- paste(matrix.2021.block.high$nut_trt, matrix.2021.block.high$ppt_trt, matrix.2021.block.high$yr, matrix.2021.block.high$block, sep = "_")

matrix.2021.block.high <- matrix.2021.block.high[, -c(0:4)]

rownames(matrix.2021.block.high) <- row.2021.block.high

matrix.bray.block.2021.high <- decostand(matrix.2021.block.high, "total")

nmds 2021

Stress: fair

0.1412997
metaMDS()
nmds.2021.block.high <- metaMDS(matrix.bray.block.2021.high, k=2, trymax = 25)
nmds.2021.block.high
stressplot(nmds.2021.block.high)
plot(nmds.2021.block.high, type="t")

nmds1.2021.block.high <- as.data.frame(scores(nmds.2021.block.high, choices=c(1), display=c("sites"))) %>%
  mutate(
    nut_trt = sapply(strsplit(rownames(matrix.2021.block.high), "_"), `[`, 1),
    ppt_trt = sapply(strsplit(rownames(matrix.2021.block.high), "_"), `[`, 2),
    yr = sapply(strsplit(rownames(matrix.2021.block.high), "_"), `[`, 3),
    block = sapply(strsplit(rownames(matrix.2021.block.high), "_"), `[`, 4)
  )
nmds2.2021.block.high <- as.data.frame(scores(nmds.2021.block.high, choices=c(2), display=c("sites")))

nmds_2021_dat.block.high <- cbind(nmds1.2021.block.high, nmds2.2021.block.high) %>%
  select(nut_trt:block, NMDS1, NMDS2)
plot
ggplot(nmds_2021_dat.block.high, aes(NMDS1, NMDS2,  color = block, shape = nut_trt)) +
  geom_point(size = 4, stroke = 0.5) +
  labs(title = "2021 (Block; HIGH) - Grouping by Block & Nutrient Treatment")

ggplot(nmds_2021_dat.block.high, aes(NMDS1, NMDS2,  fill = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; HIGH) - Grouping by Nutrient Treatment")

ggplot(nmds_2021_dat.block.high, aes(NMDS1, NMDS2,  fill = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; HIGH) - Grouping by Precipitation Treatment")

Make species x trait matrix

Greenhouse traits

  • height, leaf dry matter content, specific leaf area, root mass fraction, relative growth rate, coarse root diameter, root density, specific root length of fine roots, specific root length of coarse roots

Field traits

  • height, leaf dry matter content, specific leaf area, seed mass, leaf C, leaf N

“H1: Pairing field results with a greenhouse 15 N experiment will allow us to relate species responses to their ability to uptake organic N”

“In addition, we will conduct a greenhouse experiment to isolate the mechanism (mineralized N vs organic N uptake rates ) by which compost may affect species composition”

Workflow plan:

  • overlay species trait data as vectors on the NMDS

    • only greenhouse traits available (only sla data from field)

      • use PC scores as composite trait axes OR

      • average the traits for each species

Read in trait data

rda(traits.gh, scale = TRUE)
Error in colMeans(x, na.rm = TRUE) : 'x' must be numeric

Investigate trait data, looking in Greenhouse trait folder

Trait data is identical. Will clean data in

# dropbox.main <- read.csv("https://www.dropbox.com/scl/fi/c8vk31a807xg48jez1j03/GreenhouseTraits.csv?rlkey=ca736ea27k79mo7h8dbn67qiq&st=0h1bs53j&dl=1")
# 
# dropbox.gh <- read.csv("https://www.dropbox.com/scl/fi/67aaubdydiy4ixffmwvfe/GreenhouseTraits.csv?rlkey=rm2eqeqome7hgoedhnal0gx6d&st=vkym6evx&dl=1")
# 
# all.equal(dropbox.main, dropbox.gh)
# identical(dropbox.main, dropbox.gh)

Summarize trait data (GH) for each species

means

# make trait species ID match matrix data (notes shown below) -------
traits.cleaned <- traits.cleaned %>%
  mutate(
    ID = ifelse(
      ID == "Agoseris", "AGSP", ifelse(
        ID == "AVEBAR", "AVBA", ifelse(
          ID == "BRDR", "BRDI", ID
        )
      )
    )
  )

# summary(traits.cleaned)
traits.means <- traits.cleaned %>%
  group_by(ID) %>%
  summarise(
    across(4:(ncol(traits.gh) - 1), list(mean = ~mean(.x, na.rm = TRUE)
  )))
  

# make site by species matrix match traits species
matrix.names <- data.frame(colnames(matrix.bray)) #species comp (75 count)
trait.names <- data.frame(traits.means$ID) #trait species (80 count)

intersect.names <- intersect(colnames(matrix.bray), traits.means$ID) # same species (43 count)
setdiff(colnames(matrix.bray), traits.means$ID)
 [1] "ASSP"  "AST1"  "AST2"  "AST3"  "CIQU"  "CRTI"  "CYEC"  "DACA"  "DIMU"  "GAGR"  "GAPA"  "GAPH"  "HYSP"  "JUBU"  "LYHY" 
[16] "MAD1"  "MAD2"  "NAPU"  "PAVI"  "SABI1" "SABI2" "SIGA"  "THGR"  "TRSP"  "UNBU"  "UNF1"  "UNF3"  "UNF4"  "UNF8"  "UNFR" 
[31] "UNGR"  "XAST" 
setdiff(traits.means$ID, colnames(matrix.bray))
 [1] "ACMI"      "ANARp"     "AVFA"      "BRCA"      "BRHOp"     "BRNIf"     "BRNIp"     "CLPUf"     "CLPUp"     "CYDA"     
[11] "Crassula"  "ESCA"      "FEMI"      "FEMY"      "GITRf"     "GITRp"     "HYGL"      "LACA"      "LENIf"     "LENIp"    
[21] "LOPU"      "LUBI"      "Leontodon" "MAELf"     "MAELp"     "MICA"      "NEMA"      "PLERf"     "PLERp"     "RUPU"     
[31] "Sanicula"  "TRCI"      "TRHIpi"    "TRWIf"     "TRWIp"     "TRWIpi"    "VIVA"     
# check matrix codes to see if same species are named different things
unique.matrix.species <- cover.dat %>%
  dplyr::select(code4, species) %>%
  summarise(
    code4 = unique(code4),
    species = unique(species)
  )
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
unique.trait.species <- traits.cleaned %>%
  dplyr::select(Taxon, ID) %>%
  distinct(ID, .keep_all = TRUE)
  
  • change Trait name: ‘Agoseris’ –> ‘Agoseris unknown’; assuming the same as ‘AGSP’ –> ‘Agoseris sp.’ in matrix data (change to matrix name)

  • What’s the difference between:

    • ‘ANAR’ and ‘ANARp’ in trait data?

    • ‘BRHO’ and ‘BRHOp’ in trait data?

    • ‘BRNIf’ and ‘BRNIp’ in trait data? (not in matrix data)

    • ‘CLPUf’ and ‘CLPUp’ in trait data? (not in matrix data)

    • ‘GITRf’ and ‘GITRp’ in trait data? (not in matrix data)

    • ‘LENIf’ and ‘LENIp’ in trait data? (not in matrix data)

    • ‘TRHI’ and ‘TRHIpi’ (same sp name) in trait data? (TRHI in matrix data)

    • ‘TRWIf’ and ‘TRWIp’ and ‘TRWIpi’ in trait data? (not in matrix data)

    • ‘Crassula’ and ‘Crassula tillaea’ (could they be the same?)

    • ‘Sanicula’ (unknown) and ‘SABI1’ or ‘SABI2’ (could they be the same?)

    • ‘MAELf’ (trait data) and ‘MAD1’ (Madia sp. 1 (“tall tarweed”)’ (could they be the same?)

    • ‘MAELp’ (trait data) and ‘MAD2’ (Madia sp. 1 (“small tarweed”)’ (could they be the same?)

    • ‘Trifolium eriocephalum’ (TRER) and ‘Triphysaria eriantha’ (TRER) (could they be the same?)

  • change ‘AVEBAR’ (trait data) to ‘AVBA’ (matrix data)

  • change BRDR –> BRDI

Overlay Trait Vectors onto NMDS

ALL YEARS – LOW AND HIGH GRAZING

Prepare NMDS and Traits

Stress:

0.2011127
# trait vectors onto the NMDS
envfit(nmds.comp.trait, traits.means.comp, permutations = 999)
Warning: longer object length is not a multiple of shorter object lengthError in vectorfit(X, P, permutations, strata, choices, w = w, ...) : 
  input data have non-matching numbers of observations

Plot

ggplot(nmds_dat_trait, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Nutrient Treatment") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)


ggplot(nmds_dat_trait, aes(NMDS1, NMDS2, color = as.factor(yr), fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Year")


ggplot(nmds_dat_trait, aes(NMDS1, NMDS2, fill = as.factor(ppt_trt), color = as.factor(ppt_trt))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Precipitation Treatment") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)


ggplot(nmds_dat_trait, aes(NMDS1, NMDS2,  fill = as.factor(grazing_hist), color = as.factor(grazing_hist))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Grazing History")


ggplot(nmds_dat_trait, aes(NMDS1, NMDS2,  color = as.factor(grazing_hist), fill = as.factor(yr))) +
  geom_point(aes(fill = as.factor(yr)), shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(yr)), 
                geom = "polygon",
               fill = NA,
               size = 1) +
  labs(title = "Grouped by Grazing History & Year") +
  scale_color_manual(
  values = c(
    "low" = "cyan",
    "high" = "brown",
  "2019" = "salmon",
  "2020" = "limegreen",
  "2021" = "cornflowerblue")
  )

  
ggplot(nmds_dat_trait, aes(NMDS1, NMDS2, color = nut_trt, fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 1) +
  stat_ellipse(aes(color = as.factor(nut_trt)),
             geom = "polygon",
             fill = NA,  # Makes the ellipse transparent inside
             size = 1) +
  labs(title = "Grouped by Nutrient Treatment & Year") +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

# setdiff(colnames(matrix.bray), traits.gh.means$ID)
# setdiff(traits.gh.means$ID, colnames(matrix.bray))
traits.gh.means2 <- traits.gh.means %>%
  filter(ID %in% intersect(colnames(matrix.bray), traits.gh.means$ID))
rownames(traits.gh.means2) <- as.character(traits.gh.means2$ID)

matrix.bray %>%
  select(all_of(intersect(colnames(matrix.bray), traits.gh.means$ID))) # is this appropriate? should i relativize it all only with these species instead of just cutting out species?
nmds.comp.2 <- metaMDS(matrix.bray %>%
  select(all_of(intersect(colnames(matrix.bray), traits.gh.means$ID))), k=2, trymax = 25)
nmds.comp.2 # pretty not great stress
stressplot(nmds.comp.2)
plot(nmds.comp.2, type="t")

envfit(nmds.comp.2, traits.gh.means2, permutations = 999)
LS0tCnRpdGxlOiAiVHJhaXQgT3JkaW5hdGlvbiBQbGFudCBDb21tdW5pdHkgQW5hbHlzaXMiCmF1dGhvcjogIkNhcnluIEQuIEl3YW5hZ2EiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogeWVzCi0tLQoKIyBUcmFpdCBPcmRpbmF0aW9uIFBsYW50IENvbW11bml0eSBBbmFseXNpcwoKMS4gIHRyYWl0cwoKICAgIDEuICBhYm92ZS0gYW5kIGJlbG93Z3JvdW5kCgogICAgICAgIDEuICBoZWlnaHQgJiBTTEFcCgogICAgMi4gIGFjcXVpc2l0aXZlIHZzLiBjb25zZXJ2YXRpdmUgcmVzb3VyY2UtdXNlIHN0cmF0ZWdpZXMKCiAgICAgICAgMS4gIHJvb3RpbmcgZGVwdGgKCiAgICAzLiAgY29sbGFib3JhdGl2ZSB2cy4gaW5kaXZpZHVhbCByZXNvdXJjZS11c2Ugc3RyYXRlZ2llcwoKICAgICAgICAxLiAgZmluZSByb290IHByb3BvcnRpb24KCiAgICAgICAgMi4gIHRoaWNrbmVzcyBvZiByb290cwoKW0dvYWxdey51bmRlcmxpbmV9OiBFeGFtaW5lIGhvdyB0cmFpdHMgc2hpZnQgaW4gY29tbXVuaXR5IGNvbXBvc2l0aW9uYWwgKG9yZGluYXRpb25hbCkgc3BhY2UsIHBsYWNpbmcgZWFjaCB0cmFpdCBvbiBhbiBheGlzLgoKQXV0aG9yOiBDYXJ5biBELiBJd2FuYWdhCgpVcGRhdGVkOiAwMi8wNi8yMDI1CgojIyBMaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGh0dHIpICMgcmVhZCBvdXQgRHJvcGJveCBmb2xkZXJzCmxpYnJhcnkodmVnYW4pCmxpYnJhcnkocmVhZHhsKQpgYGAKCiMjIFJlYWQgaW4gRGF0YQoKYGBge3J9CmNvdmVyLmRhdC5sYWJlbHMgPC0gcmVhZC5jc3YoImh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3NjbC9maS91cDhubnprY3BjaHNyNDVmOGNtOTIvQ29tcG9zdF9Db3Zlcl9Mb25nQ2xlYW4uY3N2P3Jsa2V5PXoydHZhajh0NmtoYWRlZjd5ZHo3ODJ6a2Emc3Q9cXdlZjl5czAmZGw9MSIpICU+JQogIG11dGF0ZSgKICAgIG51dF90cnQgPSBmYWN0b3IoaWZlbHNlKG51dF90cnQgPT0iQyIsICIrY29tcG9zdCIsIGlmZWxzZShudXRfdHJ0ID09IkYiLCAiK04gZmVydGlsaXplciIsIGlmZWxzZShudXRfdHJ0ID09Ik4iLCAiY29udHJvbCIsIE5BKSkpLCBsZXZlbHMgPSBjKCJjb250cm9sIiwgIitOIGZlcnRpbGl6ZXIiLCAiK2NvbXBvc3QiKSksCiAgICBwcHRfdHJ0ID0gaWZlbHNlKHBwdF90cnQgPT0gIkQiLCAiZHJ5IiwgaWZlbHNlKHBwdF90cnQgPT0gIlhDIiwgImNvbnRyb2wiLCBpZmVsc2UocHB0X3RydCA9PSAiVyIsICJ3ZXQiLCBOQSkpKSkKCgojIERlZmluZSBhIHJldXNhYmxlIGNvbG9yIHNjYWxlCiMgY3VzdG9tX2NvbG9ycyA8LSBzY2FsZV9maWxsX21hbnVhbCgKIyAgIHZhbHVlcyA9IGMoCiMgICAgICJjb250cm9sIiA9IHJnYigxOTUsIDE5NywgMTkzLCBtYXhDb2xvclZhbHVlID0gMjUwKSwKIyAgICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDg3LCA2MiwgOTIsIG1heENvbG9yVmFsdWUgPSAyMjUpLAojICAgICAiK2NvbXBvc3QiID0gcmdiKDE2NywgMTU2LCAxMDksIG1heENvbG9yVmFsdWUgPSAyMjUpCiMgICApCiMgKQoKY3VzdG9tX2NvbG9ycyA8LSBzY2FsZV9maWxsX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopCgojIFNldCBhIGdsb2JhbCB0aGVtZQp0aGVtZV9zZXQodGhlbWVfYncoKSkKYGBgCgojIyBNYWtlIHNpdGUgeCBzcGVjaWVzIG1hdHJpeAoKMS4gIENhbGN1bGF0ZSByZWxhdGl2ZSBhYnVuZGFuY2VzIG9mIHNwZWNpZXMgZm9yIGVhY2ggc2l0ZQogICAgMS4gIGNvbmZ1c2VkIGhvdyB0byBhZ2dyZWdhdGUgYWJ1bmRhbmNlcyBiZWNhdXNlIGV2ZW4gZ3JvdXBpbmcgYnkgcGxvdGlkIChudXRfdHJ0IGFuZCBwcHRfdHJ0KSwgeWVhciwgc3BlY2llcywgYW5kIGdyYXppbmcgaGlzdG9yeSAoYmxvY2sgMSYyIC0tIGhpZ2gsIGJsb2NrIDMmNCAtLSBsb3cpIGFuZCBhdmVyYWdlZCwgdGhlIHNkIGFyZSBhcyBoaWdoIGFzIDQ1Ljk2IQogICAgICAgIDEuICBwcm9jZWVkZWQgd2l0aCB0aGVzZSBoaWdoIHNkIHRvIHNlZSB3aGF0IGhhcHBlbnMgKGFzayBMYXVyZW4pCiAgICAyLiAgdHJ5IGhvdyBpdCBpcyB3aGVuIHlvdSBzcGxpdCBldmVyeXRoaW5nIGJ5IGVhY2ggYmxvY2sgKG1vcmUgcmVwcmVzZW50YXRpdmU/KQoKYGBge3J9CnNpdGUuZGYgPC0gCiAgY292ZXIuZGF0LmxhYmVsc1ssIGMoMTo3LCAxODoxOSldICU+JSAjc3Vic2V0IGNvbHVtbnMKICBtdXRhdGUoCiAgICBncmF6aW5nX2hpc3QgPSBpZmVsc2UoYmxvY2sgPT0gMSB8IGJsb2NrID09IDIsICJoaWdoIiwgaWZlbHNlKGJsb2NrID09IDMgfCBibG9jayA9PSA0LCAibG93IiwgTkEpKQogICkgJT4lICMgc2VwYXJhdGUgYnkgYmxvY2sgKGdyYXppbmcgaW50ZW5zaXRpZXMpCiAgZ3JvdXBfYnkobnV0X3RydCwgcHB0X3RydCwgeXIsIGNvZGU0LCBncmF6aW5nX2hpc3QpICU+JSAjIG1ha2UgZWFjaCBjb2RlIHVuaXF1ZSAtLSBvbmUgdmFsdWUgZm9yIHNwZWNpZXMgYWJ1bmRhbmNlIGZvciBlYWNoIHRydAogIHN1bW1hcmlzZSgKICAgICMgcGN0X2NvdmVyLAogICAgYWJ1bmRhbmNlID0gbWVhbihwY3RfY292ZXIpCiAgICAjIHNkID0gc2QocGN0X2NvdmVyKQogICkKCm1hdHJpeDAgPC0gc3ByZWFkKAogIHNpdGUuZGYsIAogIGNvZGU0LCAKICBhYnVuZGFuY2UsIAogIGZpbGwgPSAwKQoKIyBtYWtlIHJvd25hbWVzIC0tLS0Kcm93bmFtZXMobWF0cml4MCkgPC0gcGFzdGUobWF0cml4MCRudXRfdHJ0LCBtYXRyaXgwJHBwdF90cnQsIG1hdHJpeDAkeXIsIG1hdHJpeDAkZ3JhemluZ19oaXN0LCBzZXAgPSAiXyIpCgojIGRlbGV0ZSBjb2x1bW5zIC0tLS0gCm1hdHJpeCA8LSBtYXRyaXgwWywgYyg1Ojc5KV0KCiMgcmVsYXRpdml6ZSBkYXRhIHdpdGggQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eQptYXRyaXguYnJheSA8LSBkZWNvc3RhbmQobWF0cml4LCAidG90YWwiKQpyb3duYW1lcyhtYXRyaXguYnJheSkgPC0gcm93bmFtZXMobWF0cml4MCkKYGBgCgojIyMgU3BsaXQgbWF0cml4IGJ5IGVhY2ggYmxvY2sgYXMgd2VsbAoKYGBge3J9CnNpdGUuYmxvY2suZGYgPC0gCiAgY292ZXIuZGF0LmxhYmVsc1ssIGMoMTo3LCAxODoxOSldICU+JSAjc3Vic2V0IGNvbHVtbnMKICBncm91cF9ieShudXRfdHJ0LCBwcHRfdHJ0LCB5ciwgY29kZTQsIGJsb2NrKSAlPiUgIyBtYWtlIGVhY2ggY29kZSB1bmlxdWUgLS0gb25lIHZhbHVlIGZvciBzcGVjaWVzIGFidW5kYW5jZSBmb3IgZWFjaCB0cnQKICBzdW1tYXJpc2UoCiAgICAjIHBjdF9jb3ZlciwKICAgIGFidW5kYW5jZSA9IG1lYW4ocGN0X2NvdmVyKQogICAgIyBzZCA9IHNkKHBjdF9jb3ZlcikKICApCgpzaXRlLmJsb2NrLnNkLmRmIDwtIAogIGNvdmVyLmRhdC5sYWJlbHNbLCBjKDE6NywgMTg6MTkpXSAlPiUgI3N1YnNldCBjb2x1bW5zCiAgZ3JvdXBfYnkobnV0X3RydCwgcHB0X3RydCwgeXIsIGNvZGU0LCBibG9jaykgJT4lICMgbWFrZSBlYWNoIGNvZGUgdW5pcXVlIC0tIG9uZSB2YWx1ZSBmb3Igc3BlY2llcyBhYnVuZGFuY2UgZm9yIGVhY2ggdHJ0CiAgc3VtbWFyaXNlKAogICAgcGN0X2NvdmVyLAogICAgYWJ1bmRhbmNlID0gbWVhbihwY3RfY292ZXIpLAogICAgc2QgPSBzZChwY3RfY292ZXIpCiAgKQoKbWF0cml4MC5ibG9jayA8LSBzcHJlYWQoCiAgc2l0ZS5ibG9jay5kZiwgCiAgY29kZTQsIAogIGFidW5kYW5jZSwgCiAgZmlsbCA9IDApCgojIG1ha2Ugcm93bmFtZXMgLS0tLQpyb3duYW1lcyhtYXRyaXgwLmJsb2NrKSA8LSBwYXN0ZShtYXRyaXgwLmJsb2NrJG51dF90cnQsIG1hdHJpeDAuYmxvY2skcHB0X3RydCwgbWF0cml4MC5ibG9jayR5ciwgbWF0cml4MC5ibG9jayRibG9jaywgc2VwID0gIl8iKQoKIyBkZWxldGUgY29sdW1ucyAtLS0tIAptYXRyaXguYmxvY2sgPC0gbWF0cml4MC5ibG9ja1ssIC1jKDA6NCldCgojIHJlbGF0aXZpemUgZGF0YSB3aXRoIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkKbWF0cml4LmJsb2NrLmJyYXkgPC0gZGVjb3N0YW5kKG1hdHJpeC5ibG9jaywgInRvdGFsIikKcm93bmFtZXMobWF0cml4LmJsb2NrLmJyYXkpIDwtIHJvd25hbWVzKG1hdHJpeDAuYmxvY2spCmBgYAoKIyMgUnVuIE5NRFMKClJ1bGVzIG9mIHRodW1iOgoKLSAgIFw8IDAuMDUgaXMgKipleGNlbGxlbnQqKgoKLSAgIDAuMDUtMC4xIGlzICoqZ29vZCoqCgotICAgMC4xLTAuMiBpcyAqKmZhaXIqKgoKLSAgIDAuMi0wLjMgKippcyBjYXVzZSBmb3IgY29uY2Vybi4uLioqCgotICAgXD4gMC4zICoqaXMgcG9vciwgcmFuZG9tKioKCiMjIyBBbGwgeWVhcnMgLS0gbG93ICYgaGlnaCBncmF6aW5nCgpbU3RyZXNzOl17LnVuZGVybGluZX0gKmZhaXIqCgpgYGAgICAgICAgICAKMC4xOTY2NTUzIApgYGAKCkdyb3VwaW5nIGJ5IHllYXIgYW5kIGdyYXppbmcgaGlzdG9yeSBoYWQgbW9zdCBzaWduaWZpY2FudCBjbHVzdGVyaW5nIHNob3duLgoKIyMjIyMgbWV0YU1EUygpCgpgYGB7cn0Kbm1kcy5jb21wIDwtIG1ldGFNRFMobWF0cml4LmJyYXksIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuY29tcCAjIHByZXR0eSBub3QgZ3JlYXQgc3RyZXNzCnN0cmVzc3Bsb3Qobm1kcy5jb21wKQpwbG90KG5tZHMuY29tcCwgdHlwZT0idCIpCgpubWRzMSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLmNvbXAsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkgJT4lCiAgbXV0YXRlKG1hdHJpeDBbLCBjKDA6NCldKQpubWRzMiA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLmNvbXAsIGNob2ljZXM9YygyKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKCm5tZHNfZGF0IDwtIGNiaW5kKG5tZHMxLCBubWRzMikgJT4lCiAgc2VsZWN0KG51dF90cnQ6Z3JhemluZ19oaXN0LCBOTURTMSwgTk1EUzIpCgpgYGAKCiMjIyMjIHBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc19kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCwgY29sb3IgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBsYWJzKHRpdGxlID0gIkdyb3VwZWQgYnkgTnV0cmllbnQgVHJlYXRtZW50IikgKwogIGN1c3RvbV9jb2xvcnMgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopCgpnZ3Bsb3Qobm1kc19kYXQsIGFlcyhOTURTMSwgTk1EUzIsIGNvbG9yID0gYXMuZmFjdG9yKHlyKSwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBZZWFyIikKCmdncGxvdChubWRzX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgZmlsbCA9IGFzLmZhY3RvcihwcHRfdHJ0KSwgY29sb3IgPSBhcy5mYWN0b3IocHB0X3RydCkpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCIpICsKICBjdXN0b21fY29sb3JzICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgdmFsdWVzID0gYygKICAgICJjb250cm9sIiA9IHJnYigyMjAsIDIyMCwgMjIwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAjIExpZ2h0ZXIgR3JheQogICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDE0MCwgNDAsIDE1MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICMgVmlicmFudCBQdXJwbGUKICAgICIrY29tcG9zdCIgPSByZ2IoMjIwLCAxODAsIDYwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAgIyBCcmlnaHQgR29sZGVuIFllbGxvdwogICAgIndldCIgPSByZ2IoMCwgMCwgMjU1LCBtYXhDb2xvclZhbHVlID0gMjU1KSwKICAgICJkcnkiID0gcmdiKDE4MywgNjUsIDE0LCBtYXhDb2xvclZhbHVlID0gMjU1KQogICkKKQoKZ2dwbG90KG5tZHNfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IGFzLmZhY3RvcihncmF6aW5nX2hpc3QpLCBjb2xvciA9IGFzLmZhY3RvcihncmF6aW5nX2hpc3QpKSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBsYWJzKHRpdGxlID0gIkdyb3VwZWQgYnkgR3JhemluZyBIaXN0b3J5IikKCmdncGxvdChubWRzX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGNvbG9yID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCksIGZpbGwgPSBhcy5mYWN0b3IoeXIpKSkgKwogIGdlb21fcG9pbnQoYWVzKGZpbGwgPSBhcy5mYWN0b3IoeXIpKSwgc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDEpICsKICBzdGF0X2VsbGlwc2UoYWVzKGNvbG9yID0gYXMuZmFjdG9yKHlyKSksIAogICAgICAgICAgICAgICAgZ2VvbSA9ICJwb2x5Z29uIiwKICAgICAgICAgICAgICAgZmlsbCA9IE5BLAogICAgICAgICAgICAgICBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBHcmF6aW5nIEhpc3RvcnkgJiBZZWFyIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImxvdyIgPSAiY3lhbiIsCiAgICAiaGlnaCIgPSAiYnJvd24iLAogICIyMDE5IiA9ICJzYWxtb24iLAogICIyMDIwIiA9ICJsaW1lZ3JlZW4iLAogICIyMDIxIiA9ICJjb3JuZmxvd2VyYmx1ZSIpCiAgKQogIApnZ3Bsb3Qobm1kc19kYXQsIGFlcyhOTURTMSwgTk1EUzIsIGNvbG9yID0gbnV0X3RydCwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMSkgKwogIHN0YXRfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IobnV0X3RydCkpLAogICAgICAgICAgICAgZ2VvbSA9ICJwb2x5Z29uIiwKICAgICAgICAgICAgIGZpbGwgPSBOQSwgICMgTWFrZXMgdGhlIGVsbGlwc2UgdHJhbnNwYXJlbnQgaW5zaWRlCiAgICAgICAgICAgICBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBOdXRyaWVudCBUcmVhdG1lbnQgJiBZZWFyIikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopCgpgYGAKCiMjIyBBbGwgeWVhcnMgLS0gYmxvY2tzCgpbU3RyZXNzOl17LnVuZGVybGluZX0gKmNhdXNlIGZvciBjb25jZXJuKgoKYGBgICAgICAgICAgCjAuMjMyOTMwNgpgYGAKCiMjIyMjIG1ldGFNRFMoKQoKYGBge3J9Cm5tZHMuYmxvY2suY29tcCA8LSBtZXRhTURTKG1hdHJpeC5ibG9jay5icmF5LCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLmJsb2NrLmNvbXAKc3RyZXNzcGxvdChubWRzLmJsb2NrLmNvbXApCnBsb3Qobm1kcy5ibG9jay5jb21wLCB0eXBlPSJ0IikKCm5tZHMxIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuYmxvY2suY29tcCwgY2hvaWNlcz1jKDEpLCBkaXNwbGF5PWMoInNpdGVzIikpKSAlPiUKICBtdXRhdGUobWF0cml4MC5ibG9ja1ssIGMoMDo0KV0pCm5tZHMyIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuYmxvY2suY29tcCwgY2hvaWNlcz1jKDIpLCBkaXNwbGF5PWMoInNpdGVzIikpKQoKbm1kc19kYXQuYmxvY2sgPC0gY2JpbmQobm1kczEsIG5tZHMyKSAlPiUKICBzZWxlY3QobnV0X3RydDpibG9jaywgTk1EUzEsIE5NRFMyKQpgYGAKCiMjIyMjIHBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc19kYXQuYmxvY2ssIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCwgY29sb3IgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBsYWJzKHRpdGxlID0gIkdyb3VwZWQgYnkgTnV0cmllbnQgVHJlYXRtZW50IC0gQmxvY2tzIikgKwogIGN1c3RvbV9jb2xvcnMgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopCgpnZ3Bsb3Qobm1kc19kYXQuYmxvY2ssIGFlcyhOTURTMSwgTk1EUzIsIGNvbG9yID0gYXMuZmFjdG9yKHlyKSwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBZZWFyIC0gQmxvY2tzIikKCmdncGxvdChubWRzX2RhdC5ibG9jaywgYWVzKE5NRFMxLCBOTURTMiwgZmlsbCA9IGFzLmZhY3RvcihwcHRfdHJ0KSwgY29sb3IgPSBhcy5mYWN0b3IocHB0X3RydCkpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCAtIEJsb2NrcyIpICsKICBjdXN0b21fY29sb3JzICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgdmFsdWVzID0gYygKICAgICJjb250cm9sIiA9IHJnYigyMjAsIDIyMCwgMjIwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAjIExpZ2h0ZXIgR3JheQogICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDE0MCwgNDAsIDE1MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICMgVmlicmFudCBQdXJwbGUKICAgICIrY29tcG9zdCIgPSByZ2IoMjIwLCAxODAsIDYwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAgIyBCcmlnaHQgR29sZGVuIFllbGxvdwogICAgIndldCIgPSByZ2IoMCwgMCwgMjU1LCBtYXhDb2xvclZhbHVlID0gMjU1KSwKICAgICJkcnkiID0gcmdiKDE4MywgNjUsIDE0LCBtYXhDb2xvclZhbHVlID0gMjU1KQogICkKKQoKZ2dwbG90KG5tZHNfZGF0LmJsb2NrLCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IGFzLmZhY3RvcihibG9jayksIGNvbG9yID0gYXMuZmFjdG9yKGJsb2NrKSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IEJsb2NrIikKCmdncGxvdChubWRzX2RhdC5ibG9jaywgYWVzKE5NRFMxLCBOTURTMiwgIGNvbG9yID0gYXMuZmFjdG9yKGJsb2NrKSwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiAgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGFzLmZhY3Rvcih5cikpLCBzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMSkgKwogIHN0YXRfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoYmxvY2spKSwgCiAgICAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAogICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IEJsb2NrICYgWWVhciAtIEJsb2NrcyIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgdmFsdWVzID0gYygKICAgICMgImxvdyIgPSAiY3lhbiIsCiAgICAjICJoaWdoIiA9ICJicm93biIsCiAgIjIwMTkiID0gInNhbG1vbiIsCiAgIjIwMjAiID0gImxpbWVncmVlbiIsCiAgIjIwMjEiID0gImNvcm5mbG93ZXJibHVlIikKICApCiAgCmdncGxvdChubWRzX2RhdC5ibG9jaywgYWVzKE5NRFMxLCBOTURTMiwgY29sb3IgPSBudXRfdHJ0LCBmaWxsID0gYXMuZmFjdG9yKHlyKSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAxKSArCiAgc3RhdF9lbGxpcHNlKGFlcyhjb2xvciA9IGFzLmZhY3RvcihudXRfdHJ0KSksCiAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAogICAgICAgICAgICAgZmlsbCA9IE5BLCAgIyBNYWtlcyB0aGUgZWxsaXBzZSB0cmFuc3BhcmVudCBpbnNpZGUKICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IE51dHJpZW50IFRyZWF0bWVudCAmIFllYXIgLSBCbG9ja3MiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikKYGBgCgojIyMgQWxsIHllYXJzIC0gTE9XIEdSQVpJTkcgT05MWQoKW1N0cmVzczpdey51bmRlcmxpbmV9ICpmYWlyKgoKYGBgICAgICAgICAgCjAuMTg2OTA2OApgYGAKCiMjIyMgZGF0YSB3cmFuZ2xpbmcKCmBgYHtyfQojIHJlbGF0aXZpemUgZGF0YSB3aXRoIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkKbWF0cml4LmxvdyA8LSBtYXRyaXgwICU+JQogIGZpbHRlcihncmF6aW5nX2hpc3QgPT0gImxvdyIpCgpyb3cubG93IDwtIHBhc3RlKG1hdHJpeC5sb3ckbnV0X3RydCwgbWF0cml4LmxvdyRwcHRfdHJ0LCBtYXRyaXgubG93JHlyLCBtYXRyaXgubG93JGdyYXppbmdfaGlzdCwgc2VwID0gIl8iKQoKbWF0cml4LmxvdyA8LSBtYXRyaXgubG93WywgYyg1Ojc5KV0KCnJvd25hbWVzKG1hdHJpeC5sb3cpIDwtIHJvdy5sb3cKCm1hdHJpeC5icmF5LmxvdyA8LSBkZWNvc3RhbmQobWF0cml4LmxvdywgInRvdGFsIikKYGBgCgojIyMjIG1ldGFNRFMoKQoKYGBge3J9Cm5tZHMuY29tcC5sb3cgPC0gbWV0YU1EUyhtYXRyaXguYnJheS5sb3csIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuY29tcC5sb3cgIyBwcmV0dHkgbm90IGdyZWF0IHN0cmVzcwpzdHJlc3NwbG90KG5tZHMuY29tcC5sb3cpCnBsb3Qobm1kcy5jb21wLmxvdywgdHlwZT0idCIpCgpubWRzMSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLmNvbXAubG93LCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpICU+JQogIG11dGF0ZSgKICAgIG51dF90cnQgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LmxvdyksICJfIiksIGBbYCwgMSksCiAgICBwcHRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC5sb3cpLCAiXyIpLCBgW2AsIDIpLAogICAgeXIgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LmxvdyksICJfIiksIGBbYCwgMyksCiAgICBncmF6aW5nX2hpc3QgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LmxvdyksICJfIiksIGBbYCwgNCkKICApCm5tZHMyIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuY29tcC5sb3csIGNob2ljZXM9YygyKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKCm5tZHNfbG93X2RhdCA8LSBjYmluZChubWRzMSwgbm1kczIpICU+JQogIHNlbGVjdChudXRfdHJ0OmdyYXppbmdfaGlzdCwgTk1EUzEsIE5NRFMyKQpgYGAKCiMjIyMgcGxvdAoKYGBge3J9CmdncGxvdChubWRzX2xvd19kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBjb2xvciA9IGFzLmZhY3Rvcih5ciksIHNoYXBlID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBzdHJva2UgPSAxKSArIAogIGxhYnModGl0bGUgPSAiMjAxOS0yMDIxIChMT1cpIC0gR3JvdXBpbmcgYnkgWWVhciAmIE51dHJpZW50IFRyZWF0bWVudCIpCgpnZ3Bsb3Qobm1kc19sb3dfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGxhYnModGl0bGUgPSAiMjAxOS0yMDIxIChMT1cpIC0gR3JvdXBpbmcgYnkgTnV0cmllbnQgVHJlYXRtZW50IikrIAogIGN1c3RvbV9jb2xvcnMKCgpnZ3Bsb3Qobm1kc19sb3dfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMTktMjAyMSAoTE9XKSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikgCgojIGFkZCB5ZWFyIGVsbGlwc2VzIC0tLS0gCmdncGxvdChubWRzX2xvd19kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgc3RhdF9lbGxpcHNlKGFlcyhjb2xvciA9IGFzLmZhY3Rvcih5cikpLCAKICAgICAgICAgICAgICAgIGdlb20gPSAicG9seWdvbiIsCiAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgc2l6ZSA9IDEpICsKICBsYWJzKHRpdGxlID0gIjIwMTktMjAyMSAoTE9XKSAtIEdyb3VwaW5nIGJ5IE51dHJpZW50IFRyZWF0bWVudCIpKyAKICBjdXN0b21fY29sb3JzCgoKZ2dwbG90KG5tZHNfbG93X2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBwcHRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICAgIHN0YXRfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoeXIpKSwgCiAgICAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAogICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAxOS0yMDIxIChMT1cpIC0gR3JvdXBpbmcgYnkgUHJlY2lwaXRhdGlvbiBUcmVhdG1lbnQiKSAKYGBgCgojIyBNYWtlIGVhY2ggaW5kaXZpZHVhbCB5ZWFyIE5NRFMgdG8gc2VlIGlmIHRoZXJlJ3MgYmV0dGVyIHN0cmVzcwoKIyMjIDIwMTkKCiMjIyMgZGF0YSB3cmFuZ2xpbmcKCmBgYHtyfQojIHJlbGF0aXZpemUgZGF0YSB3aXRoIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkKbWF0cml4LjIwMTkgPC0gbWF0cml4MCAlPiUKICBmaWx0ZXIoeXIgPT0gMjAxOSkKCnJvdy4yMDE5IDwtIHBhc3RlKG1hdHJpeC4yMDE5JG51dF90cnQsIG1hdHJpeC4yMDE5JHBwdF90cnQsIG1hdHJpeC4yMDE5JHlyLCBtYXRyaXguMjAxOSRncmF6aW5nX2hpc3QsIHNlcCA9ICJfIikKCm1hdHJpeC4yMDE5IDwtIG1hdHJpeC4yMDE5WywgYyg1Ojc5KV0KCnJvd25hbWVzKG1hdHJpeC4yMDE5KSA8LSByb3cuMjAxOQoKbWF0cml4LmJyYXkuMjAxOSA8LSBkZWNvc3RhbmQobWF0cml4LjIwMTksICJ0b3RhbCIpCmBgYAoKIyMjIyBubWRzIDIwMTkKCltTdHJlc3M6XXsudW5kZXJsaW5lfSAqRXhjZWxsZW50KgoKYGBgICAgICAgICAgCjAuMDU2MDE3OApgYGAKCiMjIyMjIG1ldGFNRFMoKQoKYGBge3J9Cm5tZHMuMjAxOSA8LSBtZXRhTURTKG1hdHJpeC5icmF5LjIwMTksIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuMjAxOSAjIHByZXR0eSBub3QgZ3JlYXQgc3RyZXNzCnN0cmVzc3Bsb3Qobm1kcy4yMDE5KQpwbG90KG5tZHMuMjAxOSwgdHlwZT0idCIpCgpubWRzMS4yMDE5IDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAxOSwgY2hvaWNlcz1jKDEpLCBkaXNwbGF5PWMoInNpdGVzIikpKSAlPiUKICBtdXRhdGUoCiAgICBudXRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDE5KSwgIl8iKSwgYFtgLCAxKSwKICAgIHBwdF90cnQgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMTkpLCAiXyIpLCBgW2AsIDIpLAogICAgeXIgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMTkpLCAiXyIpLCBgW2AsIDMpLAogICAgZ3JhemluZ19oaXN0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDE5KSwgIl8iKSwgYFtgLCA0KQogICkKbm1kczIuMjAxOSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMTksIGNob2ljZXM9YygyKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKCm5tZHNfMjAxOV9kYXQgPC0gY2JpbmQobm1kczEuMjAxOSwgbm1kczIuMjAxOSkgJT4lCiAgc2VsZWN0KG51dF90cnQ6Z3JhemluZ19oaXN0LCBOTURTMSwgTk1EUzIpCmBgYAoKIyMjIyMgcGxvdAoKYGBge3J9CmdncGxvdChubWRzXzIwMTlfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgY29sb3IgPSBncmF6aW5nX2hpc3QsIHNoYXBlID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNpemUgPSAzLCBzdHJva2UgPSAxKSArIAogIGxhYnModGl0bGUgPSAiMjAxOSAtIEdyb3VwaW5nIGJ5IEdyYXppbmcgSGlzdG9yeSAmIE51dHJpZW50IFRyZWF0bWVudCIpCgpnZ3Bsb3Qobm1kc18yMDE5X2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBsYWJzKHRpdGxlID0gIjIwMTkgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKSsgCiAgY3VzdG9tX2NvbG9ycwoKCmdncGxvdChubWRzXzIwMTlfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMTkgLSBHcm91cGluZyBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCIpIAoKYGBgCgpgYGAgICAgICAgICAKYGBgCgojIyMgMjAyMAoKIyMjIyBkYXRhIHdyYW5nbGluZwoKYGBge3J9CiMgcmVsYXRpdml6ZSBkYXRhIHdpdGggQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eQptYXRyaXguMjAyMCA8LSBtYXRyaXgwICU+JQogIGZpbHRlcih5ciA9PSAyMDIwKQoKcm93LjIwMjAgPC0gcGFzdGUobWF0cml4LjIwMjAkbnV0X3RydCwgbWF0cml4LjIwMjAkcHB0X3RydCwgbWF0cml4LjIwMjAkeXIsIG1hdHJpeC4yMDIwJGdyYXppbmdfaGlzdCwgc2VwID0gIl8iKQoKbWF0cml4LjIwMjAgPC0gbWF0cml4LjIwMjBbLCBjKDU6NzkpXQoKcm93bmFtZXMobWF0cml4LjIwMjApIDwtIHJvdy4yMDIwCgptYXRyaXguYnJheS4yMDIwIDwtIGRlY29zdGFuZChtYXRyaXguMjAyMCwgInRvdGFsIikKYGBgCgojIyMjIG5tZHMgMjAyMAoKW1N0cmVzczpdey51bmRlcmxpbmV9ICpmYWlyKgoKYGBgICAgICAgICAgCjAuMTUyMjQ5NQpgYGAKCiMjIyMjIG1ldGFNRFMoKQoKYGBge3J9Cm5tZHMuMjAyMCA8LSBtZXRhTURTKG1hdHJpeC5icmF5LjIwMjAsIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuMjAyMApzdHJlc3NwbG90KG5tZHMuMjAyMCkKcGxvdChubWRzLjIwMjAsIHR5cGU9InQiKQoKbm1kczEuMjAyMCA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMjAsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkgJT4lCiAgbXV0YXRlKAogICAgbnV0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMCksICJfIiksIGBbYCwgMSksCiAgICBwcHRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIwKSwgIl8iKSwgYFtgLCAyKSwKICAgIHlyID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIwKSwgIl8iKSwgYFtgLCAzKSwKICAgIGdyYXppbmdfaGlzdCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMCksICJfIiksIGBbYCwgNCkKICApCm5tZHMyLjIwMjAgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIwLCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzXzIwMjBfZGF0IDwtIGNiaW5kKG5tZHMxLjIwMjAsIG5tZHMyLjIwMjApICU+JQogIHNlbGVjdChudXRfdHJ0OmdyYXppbmdfaGlzdCwgTk1EUzEsIE5NRFMyKQpgYGAKCiMjIyMjIHBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc18yMDIwX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGNvbG9yID0gZ3JhemluZ19oaXN0LCBzaGFwZSA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCwgc3Ryb2tlID0gMSkgKyAKICBsYWJzKHRpdGxlID0gIjIwMjAgLSBHcm91cGluZyBieSBHcmF6aW5nIEhpc3RvcnkgJiBOdXRyaWVudCBUcmVhdG1lbnQiKSAKCmdncGxvdChubWRzXzIwMjBfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjAgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMF9kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gcHB0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMCAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyMgMjAyMQoKIyMjIyBkYXRhIHdyYW5nbGluZwoKYGBge3J9CiMgcmVsYXRpdml6ZSBkYXRhIHdpdGggQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eQptYXRyaXguMjAyMSA8LSBtYXRyaXgwICU+JQogIGZpbHRlcih5ciA9PSAyMDIxKQoKcm93LjIwMjEgPC0gcGFzdGUobWF0cml4LjIwMjEkbnV0X3RydCwgbWF0cml4LjIwMjEkcHB0X3RydCwgbWF0cml4LjIwMjEkeXIsIG1hdHJpeC4yMDIxJGdyYXppbmdfaGlzdCwgc2VwID0gIl8iKQoKbWF0cml4LjIwMjEgPC0gbWF0cml4LjIwMjFbLCBjKDU6NzkpXQoKcm93bmFtZXMobWF0cml4LjIwMjEpIDwtIHJvdy4yMDIxCgptYXRyaXguYnJheS4yMDIxIDwtIGRlY29zdGFuZChtYXRyaXguMjAyMSwgInRvdGFsIikKYGBgCgojIyMjIyAyMDIxIC0gTE9XCgpTdHJlc3MKCmBgYCAgICAgICAgIAowLjA4MDY3Nzg5CmBgYAoKYGBge3J9CiMgcmVsYXRpdml6ZSBkYXRhIHdpdGggQnJheS1DdXJ0aXMgZGlzc2ltaWxhcml0eQptYXRyaXguMjAyMS4xIDwtIG1hdHJpeDAgJT4lCiAgZmlsdGVyKHlyID09IDIwMjEsCiAgICAgICAgIGdyYXppbmdfaGlzdCA9PSAibG93IikgCgpyb3cuMjAyMS4xIDwtIHBhc3RlKG1hdHJpeC4yMDIxLjEkbnV0X3RydCwgbWF0cml4LjIwMjEuMSRwcHRfdHJ0LCBtYXRyaXguMjAyMS4xJHlyLCBtYXRyaXguMjAyMS4xJGdyYXppbmdfaGlzdCwgc2VwID0gIl8iKQoKbWF0cml4LjIwMjEuMSA8LSBtYXRyaXguMjAyMS4xWywgYyg1Ojc5KV0KCnJvd25hbWVzKG1hdHJpeC4yMDIxLjEpIDwtIHJvdy4yMDIxLjEKCm1hdHJpeC5icmF5LjIwMjEuMSA8LSBkZWNvc3RhbmQobWF0cml4LjIwMjEuMSwgInRvdGFsIikKYGBgCgpgYGB7cn0Kbm1kcy4yMDIxLjEgPC0gbWV0YU1EUyhtYXRyaXguYnJheS4yMDIxLjEsIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuMjAyMS4xCnN0cmVzc3Bsb3Qobm1kcy4yMDIxLjEpCnBsb3Qobm1kcy4yMDIxLjEsIHR5cGU9InQiKQpkdW1teSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMjEuMSwgY2hvaWNlcz1jKDEpLCBkaXNwbGF5PWMoInNpdGVzIikpKQoKbm1kczEuMjAyMS4xLmRmIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS4xLCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpICU+JQogIG11dGF0ZSh0cnQgPSByb3duYW1lcyhkdW1teSkpICU+JQogIHNlcGFyYXRlKHRydCwgYygibnV0X3RydCIsICJwcHRfdHJ0IiwgInByIiwgImdyYXppbmdfaGlzdCIpLCBzZXA9Il8iKQoKbm1kczIuMjAyMS4xIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS4xLCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzXzIwMjFfZGF0LjEgPC0gY2JpbmQobm1kczEuMjAyMS4xLmRmLCBubWRzMi4yMDIxLjEpICU+JQogIHNlbGVjdChudXRfdHJ0OmdyYXppbmdfaGlzdCwgTk1EUzEsIE5NRFMyKQpgYGAKCmBgYHtyfQojIGdncGxvdChubWRzXzIwMjFfZGF0LjEsIGFlcyhOTURTMSwgTk1EUzIsICBjb2xvciA9IGdyYXppbmdfaGlzdCwgc2hhcGUgPSBudXRfdHJ0KSkgKwojICAgZ2VvbV9wb2ludChzaXplID0gNCwgc3Ryb2tlID0gMC41KSArCiMgICBsYWJzKHRpdGxlID0gIjIwMjEgLSBHcm91cGluZyBieSBHcmF6aW5nIEhpc3RvcnkgJiBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMV9kYXQuMSwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDIxIChMT1cpIC0gR3JvdXBpbmcgYnkgTnV0cmllbnQgVHJlYXRtZW50IikKCmdncGxvdChubWRzXzIwMjFfZGF0LjEsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gcHB0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMSAoTE9XKSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyMjIyAyMDIxIC0gSElHSAoKU3RyZXNzCgpgYGAgICAgICAgICAKMC4wODA2NTAzNApgYGAKCmBgYHtyfQojIHJlbGF0aXZpemUgZGF0YSB3aXRoIEJyYXktQ3VydGlzIGRpc3NpbWlsYXJpdHkKbWF0cml4LjIwMjEuMiA8LSBtYXRyaXgwICU+JQogIGZpbHRlcih5ciA9PSAyMDIxLAogICAgICAgICBncmF6aW5nX2hpc3QgPT0gImhpZ2giKSAKCnJvdy4yMDIxLjIgPC0gcGFzdGUobWF0cml4LjIwMjEuMiRudXRfdHJ0LCBtYXRyaXguMjAyMS4yJHBwdF90cnQsIG1hdHJpeC4yMDIxLjIkeXIsIG1hdHJpeC4yMDIxLjIkZ3JhemluZ19oaXN0LCBzZXAgPSAiXyIpCgptYXRyaXguMjAyMS4yIDwtIG1hdHJpeC4yMDIxLjJbLCBjKDU6NzkpXQoKcm93bmFtZXMobWF0cml4LjIwMjEuMikgPC0gcm93LjIwMjEuMgoKbWF0cml4LmJyYXkuMjAyMS4yIDwtIGRlY29zdGFuZChtYXRyaXguMjAyMS4yLCAidG90YWwiKQpgYGAKCmBgYHtyfQpubWRzLjIwMjEuMiA8LSBtZXRhTURTKG1hdHJpeC5icmF5LjIwMjEuMiwgaz0yLCB0cnltYXggPSAyNSkKbm1kcy4yMDIxLjIKc3RyZXNzcGxvdChubWRzLjIwMjEuMikKcGxvdChubWRzLjIwMjEuMiwgdHlwZT0idCIpCmR1bW15IDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS4yLCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzMS4yMDIxLjIuZGYgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLjIsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkgJT4lCiAgbXV0YXRlKHRydCA9IHJvd25hbWVzKGR1bW15KSkgJT4lCiAgc2VwYXJhdGUodHJ0LCBjKCJudXRfdHJ0IiwgInBwdF90cnQiLCAicHIiLCAiZ3JhemluZ19oaXN0IiksIHNlcD0iXyIpCgpubWRzMi4yMDIxLjIgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLjIsIGNob2ljZXM9YygyKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKCm5tZHNfMjAyMV9kYXQuMiA8LSBjYmluZChubWRzMS4yMDIxLjIuZGYsIG5tZHMyLjIwMjEuMikgJT4lCiAgc2VsZWN0KG51dF90cnQ6Z3JhemluZ19oaXN0LCBOTURTMSwgTk1EUzIpCmBgYAoKYGBge3J9CmdncGxvdChubWRzXzIwMjFfZGF0LjIsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMSAoSElHSCkgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMV9kYXQuMiwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBwcHRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDIxIChISUdIKSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyMjIG5tZHMgMjAyMQoKW1N0cmVzczpdey51bmRlcmxpbmV9ICpmYWlyKgoKYGBgICAgICAgICAgCjAuMTIzMDgzMQpgYGAKCiMjIyMjIG1ldGFNRFMoKQoKYGBge3J9Cm5tZHMuMjAyMSA8LSBtZXRhTURTKG1hdHJpeC5icmF5LjIwMjEsIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuMjAyMQpzdHJlc3NwbG90KG5tZHMuMjAyMSkKcGxvdChubWRzLjIwMjEsIHR5cGU9InQiKQoKbm1kczEuMjAyMSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMjEsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkgJT4lCiAgbXV0YXRlKAogICAgbnV0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMSksICJfIiksIGBbYCwgMSksCiAgICBwcHRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIxKSwgIl8iKSwgYFtgLCAyKSwKICAgIHlyID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIxKSwgIl8iKSwgYFtgLCAzKSwKICAgIGdyYXppbmdfaGlzdCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMSksICJfIiksIGBbYCwgNCkKICApCm5tZHMyLjIwMjEgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzXzIwMjFfZGF0IDwtIGNiaW5kKG5tZHMxLjIwMjEsIG5tZHMyLjIwMjEpICU+JQogIHNlbGVjdChudXRfdHJ0OmdyYXppbmdfaGlzdCwgTk1EUzEsIE5NRFMyKQpgYGAKCiMjIyMjIHBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc18yMDIxX2RhdCwgYWVzKE5NRFMxLCBOTURTMiwgIGNvbG9yID0gZ3JhemluZ19oaXN0LCBzaGFwZSA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCwgc3Ryb2tlID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICIyMDIxIC0gR3JvdXBpbmcgYnkgR3JhemluZyBIaXN0b3J5ICYgTnV0cmllbnQgVHJlYXRtZW50IikKCmdncGxvdChubWRzXzIwMjFfZGF0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMV9kYXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gcHB0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyMgMjAyMSAtLS0gYmxvY2tzCgojIyMjIGRhdGEgd3JhbmdsaW5nCgpgYGB7cn0KIyByZWxhdGl2aXplIGRhdGEgd2l0aCBCcmF5LUN1cnRpcyBkaXNzaW1pbGFyaXR5Cm1hdHJpeC4yMDIxLmJsb2NrIDwtIG1hdHJpeDAuYmxvY2sgJT4lCiAgZmlsdGVyKHlyID09IDIwMjEpCgpyb3cuMjAyMS5ibG9jayA8LSBwYXN0ZShtYXRyaXguMjAyMS5ibG9jayRudXRfdHJ0LCBtYXRyaXguMjAyMS5ibG9jayRwcHRfdHJ0LCBtYXRyaXguMjAyMS5ibG9jayR5ciwgbWF0cml4LjIwMjEuYmxvY2skYmxvY2ssIHNlcCA9ICJfIikKCm1hdHJpeC4yMDIxLmJsb2NrIDwtIG1hdHJpeC4yMDIxLmJsb2NrWywgYyg1Ojc5KV0KCnJvd25hbWVzKG1hdHJpeC4yMDIxLmJsb2NrKSA8LSByb3cuMjAyMS5ibG9jawoKbWF0cml4LmJyYXkuYmxvY2suMjAyMSA8LSBkZWNvc3RhbmQobWF0cml4LjIwMjEuYmxvY2ssICJ0b3RhbCIpCmBgYAoKIyMjIyBubWRzIDIwMjEKCltTdHJlc3M6XXsudW5kZXJsaW5lfSAqZmFpcioKCmBgYCAgICAgICAgIAowLjE3MDI5NDQKYGBgCgojIyMjIyBtZXRhTURTKCkKCmBgYHtyfQpubWRzLjIwMjEuYmxvY2sgPC0gbWV0YU1EUyhtYXRyaXguYnJheS5ibG9jay4yMDIxLCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLjIwMjEuYmxvY2sKc3RyZXNzcGxvdChubWRzLjIwMjEuYmxvY2spCnBsb3Qobm1kcy4yMDIxLmJsb2NrLCB0eXBlPSJ0IikKCm5tZHMxLjIwMjEuYmxvY2sgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLmJsb2NrLCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpICU+JQogIG11dGF0ZSgKICAgIG51dF90cnQgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjEuYmxvY2spLCAiXyIpLCBgW2AsIDEpLAogICAgcHB0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jayksICJfIiksIGBbYCwgMiksCiAgICB5ciA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jayksICJfIiksIGBbYCwgMyksCiAgICBibG9jayA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jayksICJfIiksIGBbYCwgNCkKICApCm5tZHMyLjIwMjEuYmxvY2sgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLmJsb2NrLCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzXzIwMjFfZGF0LmJsb2NrIDwtIGNiaW5kKG5tZHMxLjIwMjEuYmxvY2ssIG5tZHMyLjIwMjEuYmxvY2spICU+JQogIHNlbGVjdChudXRfdHJ0OmJsb2NrLCBOTURTMSwgTk1EUzIpCmBgYAoKIyMjIyMgcGxvdAoKYGBge3J9CmdncGxvdChubWRzXzIwMjFfZGF0LmJsb2NrLCBhZXMoTk1EUzEsIE5NRFMyLCAgY29sb3IgPSBibG9jaywgc2hhcGUgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKwogIGxhYnModGl0bGUgPSAiMjAyMSAoQmxvY2spIC0gR3JvdXBpbmcgYnkgQmxvY2sgJiBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMV9kYXQuYmxvY2ssIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMSAoQmxvY2spIC0gR3JvdXBpbmcgYnkgTnV0cmllbnQgVHJlYXRtZW50IikKCmdncGxvdChubWRzXzIwMjFfZGF0LmJsb2NrLCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgKEJsb2NrKSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyMgMjAyMSAtLS0gYmxvY2tzIChMT1cpCgojIyMjIGRhdGEgd3JhbmdsaW5nCgpgYGB7cn0KIyByZWxhdGl2aXplIGRhdGEgd2l0aCBCcmF5LUN1cnRpcyBkaXNzaW1pbGFyaXR5Cm1hdHJpeC4yMDIxLmJsb2NrLmxvdyA8LSBtYXRyaXgwLmJsb2NrICU+JQogIGZpbHRlcih5ciA9PSAyMDIxLAogICAgICAgICBibG9jayA9PSAzIHwgYmxvY2sgPT0gNCkKCnJvdy4yMDIxLmJsb2NrLmxvdyA8LSBwYXN0ZShtYXRyaXguMjAyMS5ibG9jay5sb3ckbnV0X3RydCwgbWF0cml4LjIwMjEuYmxvY2subG93JHBwdF90cnQsIG1hdHJpeC4yMDIxLmJsb2NrLmxvdyR5ciwgbWF0cml4LjIwMjEuYmxvY2subG93JGJsb2NrLCBzZXAgPSAiXyIpCgptYXRyaXguMjAyMS5ibG9jay5sb3cgPC0gbWF0cml4LjIwMjEuYmxvY2subG93WywgLWMoMDo0KV0KCnJvd25hbWVzKG1hdHJpeC4yMDIxLmJsb2NrLmxvdykgPC0gcm93LjIwMjEuYmxvY2subG93CgptYXRyaXguYnJheS5ibG9jay4yMDIxLmxvdyA8LSBkZWNvc3RhbmQobWF0cml4LjIwMjEuYmxvY2subG93LCAidG90YWwiKQpgYGAKCiMjIyMgbm1kcyAyMDIxCgpbU3RyZXNzOl17LnVuZGVybGluZX0gKmZhaXIqCgpgYGAgICAgICAgICAKMC4xMjgyMjk2CmBgYAoKIyMjIyMgbWV0YU1EUygpCgpgYGB7cn0Kbm1kcy4yMDIxLmJsb2NrLmxvdyA8LSBtZXRhTURTKG1hdHJpeC5icmF5LmJsb2NrLjIwMjEubG93LCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLjIwMjEuYmxvY2subG93CnN0cmVzc3Bsb3Qobm1kcy4yMDIxLmJsb2NrLmxvdykKcGxvdChubWRzLjIwMjEuYmxvY2subG93LCB0eXBlPSJ0IikKCm5tZHMxLjIwMjEuYmxvY2subG93IDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS5ibG9jay5sb3csIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkgJT4lCiAgbXV0YXRlKAogICAgbnV0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jay5sb3cpLCAiXyIpLCBgW2AsIDEpLAogICAgcHB0X3RydCA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jay5sb3cpLCAiXyIpLCBgW2AsIDIpLAogICAgeXIgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjEuYmxvY2subG93KSwgIl8iKSwgYFtgLCAzKSwKICAgIGJsb2NrID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIxLmJsb2NrLmxvdyksICJfIiksIGBbYCwgNCkKICApCm5tZHMyLjIwMjEuYmxvY2subG93IDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS5ibG9jay5sb3csIGNob2ljZXM9YygyKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKCm5tZHNfMjAyMV9kYXQuYmxvY2subG93IDwtIGNiaW5kKG5tZHMxLjIwMjEuYmxvY2subG93LCBubWRzMi4yMDIxLmJsb2NrLmxvdykgJT4lCiAgc2VsZWN0KG51dF90cnQ6YmxvY2ssIE5NRFMxLCBOTURTMikKYGBgCgojIyMjIyBwbG90CgpgYGB7cn0KZ2dwbG90KG5tZHNfMjAyMV9kYXQuYmxvY2subG93LCBhZXMoTk1EUzEsIE5NRFMyLCAgY29sb3IgPSBibG9jaywgc2hhcGUgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKwogIGxhYnModGl0bGUgPSAiMjAyMSAoQmxvY2s7IExPVykgLSBHcm91cGluZyBieSBCbG9jayAmIE51dHJpZW50IFRyZWF0bWVudCIpCgpnZ3Bsb3Qobm1kc18yMDIxX2RhdC5ibG9jay5sb3csIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAyMSAoQmxvY2s7IExPVykgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKQoKZ2dwbG90KG5tZHNfMjAyMV9kYXQuYmxvY2subG93LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgKEJsb2NrOyBMT1cpIC0gR3JvdXBpbmcgYnkgUHJlY2lwaXRhdGlvbiBUcmVhdG1lbnQiKQpgYGAKCiMjIyAyMDIxIC0tLSBibG9ja3MgKEhJR0gpCgojIyMjIGRhdGEgd3JhbmdsaW5nCgpgYGB7cn0KIyByZWxhdGl2aXplIGRhdGEgd2l0aCBCcmF5LUN1cnRpcyBkaXNzaW1pbGFyaXR5Cm1hdHJpeC4yMDIxLmJsb2NrLmhpZ2ggPC0gbWF0cml4MC5ibG9jayAlPiUKICBmaWx0ZXIoeXIgPT0gMjAyMSwKICAgICAgICAgYmxvY2sgPT0gMSB8IGJsb2NrID09IDIpCgpyb3cuMjAyMS5ibG9jay5oaWdoIDwtIHBhc3RlKG1hdHJpeC4yMDIxLmJsb2NrLmhpZ2gkbnV0X3RydCwgbWF0cml4LjIwMjEuYmxvY2suaGlnaCRwcHRfdHJ0LCBtYXRyaXguMjAyMS5ibG9jay5oaWdoJHlyLCBtYXRyaXguMjAyMS5ibG9jay5oaWdoJGJsb2NrLCBzZXAgPSAiXyIpCgptYXRyaXguMjAyMS5ibG9jay5oaWdoIDwtIG1hdHJpeC4yMDIxLmJsb2NrLmhpZ2hbLCAtYygwOjQpXQoKcm93bmFtZXMobWF0cml4LjIwMjEuYmxvY2suaGlnaCkgPC0gcm93LjIwMjEuYmxvY2suaGlnaAoKbWF0cml4LmJyYXkuYmxvY2suMjAyMS5oaWdoIDwtIGRlY29zdGFuZChtYXRyaXguMjAyMS5ibG9jay5oaWdoLCAidG90YWwiKQpgYGAKCiMjIyMgbm1kcyAyMDIxCgpbU3RyZXNzOl17LnVuZGVybGluZX0gKmZhaXIqCgpgYGAgICAgICAgICAKMC4xNDEyOTk3CmBgYAoKIyMjIyMgbWV0YU1EUygpCgpgYGB7cn0Kbm1kcy4yMDIxLmJsb2NrLmhpZ2ggPC0gbWV0YU1EUyhtYXRyaXguYnJheS5ibG9jay4yMDIxLmhpZ2gsIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuMjAyMS5ibG9jay5oaWdoCnN0cmVzc3Bsb3Qobm1kcy4yMDIxLmJsb2NrLmhpZ2gpCnBsb3Qobm1kcy4yMDIxLmJsb2NrLmhpZ2gsIHR5cGU9InQiKQoKbm1kczEuMjAyMS5ibG9jay5oaWdoIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS5ibG9jay5oaWdoLCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpICU+JQogIG11dGF0ZSgKICAgIG51dF90cnQgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjEuYmxvY2suaGlnaCksICJfIiksIGBbYCwgMSksCiAgICBwcHRfdHJ0ID0gc2FwcGx5KHN0cnNwbGl0KHJvd25hbWVzKG1hdHJpeC4yMDIxLmJsb2NrLmhpZ2gpLCAiXyIpLCBgW2AsIDIpLAogICAgeXIgPSBzYXBwbHkoc3Ryc3BsaXQocm93bmFtZXMobWF0cml4LjIwMjEuYmxvY2suaGlnaCksICJfIiksIGBbYCwgMyksCiAgICBibG9jayA9IHNhcHBseShzdHJzcGxpdChyb3duYW1lcyhtYXRyaXguMjAyMS5ibG9jay5oaWdoKSwgIl8iKSwgYFtgLCA0KQogICkKbm1kczIuMjAyMS5ibG9jay5oaWdoIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS5ibG9jay5oaWdoLCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzXzIwMjFfZGF0LmJsb2NrLmhpZ2ggPC0gY2JpbmQobm1kczEuMjAyMS5ibG9jay5oaWdoLCBubWRzMi4yMDIxLmJsb2NrLmhpZ2gpICU+JQogIHNlbGVjdChudXRfdHJ0OmJsb2NrLCBOTURTMSwgTk1EUzIpCmBgYAoKIyMjIyMgcGxvdAoKYGBge3J9CmdncGxvdChubWRzXzIwMjFfZGF0LmJsb2NrLmhpZ2gsIGFlcyhOTURTMSwgTk1EUzIsICBjb2xvciA9IGJsb2NrLCBzaGFwZSA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCwgc3Ryb2tlID0gMC41KSArCiAgbGFicyh0aXRsZSA9ICIyMDIxIChCbG9jazsgSElHSCkgLSBHcm91cGluZyBieSBCbG9jayAmIE51dHJpZW50IFRyZWF0bWVudCIpCgpnZ3Bsb3Qobm1kc18yMDIxX2RhdC5ibG9jay5oaWdoLCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgKEJsb2NrOyBISUdIKSAtIEdyb3VwaW5nIGJ5IE51dHJpZW50IFRyZWF0bWVudCIpCgpnZ3Bsb3Qobm1kc18yMDIxX2RhdC5ibG9jay5oaWdoLCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgKEJsb2NrOyBISUdIKSAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikKYGBgCgojIyBNYWtlIHNwZWNpZXMgeCB0cmFpdCBtYXRyaXgKCkdyZWVuaG91c2UgdHJhaXRzCgotICAgaGVpZ2h0LCBsZWFmIGRyeSBtYXR0ZXIgY29udGVudCwgc3BlY2lmaWMgbGVhZiBhcmVhLCByb290IG1hc3MgZnJhY3Rpb24sIHJlbGF0aXZlIGdyb3d0aCByYXRlLCBjb2Fyc2Ugcm9vdCBkaWFtZXRlciwgcm9vdCBkZW5zaXR5LCBzcGVjaWZpYyByb290IGxlbmd0aCBvZiBmaW5lIHJvb3RzLCBzcGVjaWZpYyByb290IGxlbmd0aCBvZiBjb2Fyc2Ugcm9vdHMKCkZpZWxkIHRyYWl0cwoKLSAgIGhlaWdodCwgbGVhZiBkcnkgbWF0dGVyIGNvbnRlbnQsIHNwZWNpZmljIGxlYWYgYXJlYSwgc2VlZCBtYXNzLCBsZWFmIEMsIGxlYWYgTgoKWyJIMTpdey51bmRlcmxpbmV9IFBhaXJpbmcgZmllbGQgcmVzdWx0cyB3aXRoIGEgZ3JlZW5ob3VzZSAxNSBOIGV4cGVyaW1lbnQgd2lsbCBhbGxvdyB1cyB0byByZWxhdGUgc3BlY2llcyByZXNwb25zZXMgdG8gdGhlaXIgYWJpbGl0eSB0byB1cHRha2Ugb3JnYW5pYyBOIgoKIkluIGFkZGl0aW9uLCB3ZSB3aWxsIGNvbmR1Y3QgYSBncmVlbmhvdXNlIGV4cGVyaW1lbnQgdG8gaXNvbGF0ZSB0aGUgbWVjaGFuaXNtIChtaW5lcmFsaXplZCBOIHZzIG9yZ2FuaWMgTiB1cHRha2UgcmF0ZXMgKSBieSB3aGljaCBjb21wb3N0IG1heSBhZmZlY3Qgc3BlY2llcyBjb21wb3NpdGlvbiIKCldvcmtmbG93IHBsYW46CgotICAgb3ZlcmxheSBzcGVjaWVzIHRyYWl0IGRhdGEgYXMgdmVjdG9ycyBvbiB0aGUgTk1EUwoKICAgIC0gICBvbmx5IGdyZWVuaG91c2UgdHJhaXRzIGF2YWlsYWJsZSAob25seSBzbGEgZGF0YSBmcm9tIGZpZWxkKQoKICAgICAgICAtICAgdXNlIFBDIHNjb3JlcyBhcyBjb21wb3NpdGUgdHJhaXQgYXhlcyBPUgoKICAgICAgICAtICAgYXZlcmFnZSB0aGUgdHJhaXRzIGZvciBlYWNoIHNwZWNpZXMKCiMjIyBSZWFkIGluIHRyYWl0IGRhdGEKCmBgYHtyfQojICMgcmVhZCBpbiBncmVlbmhvdXNlIHRyYWl0IGRhdGEKIyB0cmFpdHMuZ2ggPC0gcmVhZC5jc3YoImh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3NjbC9maS9jOHZrMzFhODA3eGc0OGplejFqMDMvR3JlZW5ob3VzZVRyYWl0cy5jc3Y/cmxrZXk9Y2E3MzZlYTI3azc5bW83aDhkYm42N3FpcSZzdD15YTFjazZwNyZkbD0xIikKIyAKIyAjIHJlYWQgaW4gZmllbGQgdHJhaXQgZGF0YQojICMgZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vc2NsL2ZpL3RycXJuejU0ZGtqb2E5ZG80dGxlNS9sZWFmLWFyZWEtZGF0YV9ORy54bHN4P3Jsa2V5PXMwa2ljMmE1eXFrbmlrYzRpY2VrOHk3cm4mc3Q9ZGw0eDYzNGgmZGw9MSIsZGVzdGZpbGUgPSAiZmllbGRfc2xhLnhsc3giKQojIHRyYWl0cy5zbGEuZmllbGQgPC0gCiMgICByZWFkX2V4Y2VsKCJmaWVsZF9zbGEueGxzeCIsY29sX25hbWVzID0gVFJVRSxjb2xfdHlwZXMgPSAidGV4dCIpCiMgCiMgcmRhKHRyYWl0cy5naCwgc2NhbGUgPSBUUlVFKQpgYGAKCiMjIyMgSW52ZXN0aWdhdGUgdHJhaXQgZGF0YSwgbG9va2luZyBpbiBHcmVlbmhvdXNlIHRyYWl0IGZvbGRlcgoKVHJhaXQgZGF0YSBpcyBpZGVudGljYWwuIFdpbGwgY2xlYW4gZGF0YSBpbgoKYGBge3J9CiMgZHJvcGJveC5tYWluIDwtIHJlYWQuY3N2KCJodHRwczovL3d3dy5kcm9wYm94LmNvbS9zY2wvZmkvYzh2azMxYTgwN3hnNDhqZXoxajAzL0dyZWVuaG91c2VUcmFpdHMuY3N2P3Jsa2V5PWNhNzM2ZWEyN2s3OW1vN2g4ZGJuNjdxaXEmc3Q9MGgxYnM1M2omZGw9MSIpCiMgCiMgZHJvcGJveC5naCA8LSByZWFkLmNzdigiaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vc2NsL2ZpLzY3YWF1YmR5ZGl5NGl4ZmZtd3ZmZS9HcmVlbmhvdXNlVHJhaXRzLmNzdj9ybGtleT1ybTJlcWVxb21lN2hnb2VkaG5hbDBneDZkJnN0PXZreW02ZXZ4JmRsPTEiKQojIAojIGFsbC5lcXVhbChkcm9wYm94Lm1haW4sIGRyb3Bib3guZ2gpCiMgaWRlbnRpY2FsKGRyb3Bib3gubWFpbiwgZHJvcGJveC5naCkKYGBgCgpgYGB7cn0KdHJhaXRzLmNsZWFuZWQgPC0gcmVhZC5jc3YoImRhdGEvR3JlZW5ob3VzZVRyYWl0c19jb3JyZWN0ZWRfMjAyNDAyMTIuY3N2IikgJT4lCiAgbXV0YXRlKAogICAgRnJlc2gubGVhZi5tYXNzLi5nLiA9IGFzLm51bWVyaWMoaWZlbHNlKAogICAgICBGcmVzaC5sZWFmLm1hc3MuLmcuID09ICJTa2lwcGVkIGFjY2lkZW50YWxseSIsIE5BLCBGcmVzaC5sZWFmLm1hc3MuLmcuCiAgICApKSwKICAgIERyeS5sZWFmLm1hc3MuLmcuID0gYXMubnVtZXJpYyhpZmVsc2UoCiAgICAgIERyeS5sZWFmLm1hc3MuLmcuID09ICJObyBzYW1wbGUiLCBOQSwgRHJ5LmxlYWYubWFzcy4uZy4KICAgICkpLAogICAgUm9vdC5kcnkuYmlvbWFzcy4uZy4gPSBhcy5udW1lcmljKGlmZWxzZSgKICAgICAgUm9vdC5kcnkuYmlvbWFzcy4uZy4gPT0gInJvb3RzIGxvc3QiLCBOQSwgUm9vdC5kcnkuYmlvbWFzcy4uZy4KICAgICkpLAogICAgUm9vdC52b2x1bWUuLmNtMy4gPSBhcy5udW1lcmljKGlmZWxzZSgKICAgICAgUm9vdC52b2x1bWUuLmNtMy4gPT0gIm5vdCBzY2FubmVkIiwgTkEsIFJvb3Qudm9sdW1lLi5jbTMuCiAgICApKQogICkgCmBgYAoKIyMjIFN1bW1hcml6ZSB0cmFpdCBkYXRhIChHSCkgZm9yIGVhY2ggc3BlY2llcwoKIyMjIyBtZWFucwoKYGBge3J9CiMgbWFrZSB0cmFpdCBzcGVjaWVzIElEIG1hdGNoIG1hdHJpeCBkYXRhIChub3RlcyBzaG93biBiZWxvdykgLS0tLS0tLQp0cmFpdHMuY2xlYW5lZCA8LSB0cmFpdHMuY2xlYW5lZCAlPiUKICBtdXRhdGUoCiAgICBJRCA9IGlmZWxzZSgKICAgICAgSUQgPT0gIkFnb3NlcmlzIiwgIkFHU1AiLCBpZmVsc2UoCiAgICAgICAgSUQgPT0gIkFWRUJBUiIsICJBVkJBIiwgaWZlbHNlKAogICAgICAgICAgSUQgPT0gIkJSRFIiLCAiQlJESSIsIElECiAgICAgICAgKQogICAgICApCiAgICApCiAgKQoKIyBzdW1tYXJ5KHRyYWl0cy5jbGVhbmVkKQp0cmFpdHMubWVhbnMgPC0gdHJhaXRzLmNsZWFuZWQgJT4lCiAgZ3JvdXBfYnkoSUQpICU+JQogIHN1bW1hcmlzZSgKICAgIGFjcm9zcyg0OihuY29sKHRyYWl0cy5naCkgLSAxKSwgbGlzdChtZWFuID0gfm1lYW4oLngsIG5hLnJtID0gVFJVRSkKICApKSkKICAKCiMgbWFrZSBzaXRlIGJ5IHNwZWNpZXMgbWF0cml4IG1hdGNoIHRyYWl0cyBzcGVjaWVzCm1hdHJpeC5uYW1lcyA8LSBkYXRhLmZyYW1lKGNvbG5hbWVzKG1hdHJpeC5icmF5KSkgI3NwZWNpZXMgY29tcCAoNzUgY291bnQpCnRyYWl0Lm5hbWVzIDwtIGRhdGEuZnJhbWUodHJhaXRzLm1lYW5zJElEKSAjdHJhaXQgc3BlY2llcyAoODAgY291bnQpCgppbnRlcnNlY3QubmFtZXMgPC0gaW50ZXJzZWN0KGNvbG5hbWVzKG1hdHJpeC5icmF5KSwgdHJhaXRzLm1lYW5zJElEKSAjIHNhbWUgc3BlY2llcyAoNDMgY291bnQpCnNldGRpZmYoY29sbmFtZXMobWF0cml4LmJyYXkpLCB0cmFpdHMubWVhbnMkSUQpCnNldGRpZmYodHJhaXRzLm1lYW5zJElELCBjb2xuYW1lcyhtYXRyaXguYnJheSkpCgojIGNoZWNrIG1hdHJpeCBjb2RlcyB0byBzZWUgaWYgc2FtZSBzcGVjaWVzIGFyZSBuYW1lZCBkaWZmZXJlbnQgdGhpbmdzCnVuaXF1ZS5tYXRyaXguc3BlY2llcyA8LSBjb3Zlci5kYXQgJT4lCiAgZHBseXI6OnNlbGVjdChjb2RlNCwgc3BlY2llcykgJT4lCiAgc3VtbWFyaXNlKAogICAgY29kZTQgPSB1bmlxdWUoY29kZTQpLAogICAgc3BlY2llcyA9IHVuaXF1ZShzcGVjaWVzKQogICkKCnVuaXF1ZS50cmFpdC5zcGVjaWVzIDwtIHRyYWl0cy5jbGVhbmVkICU+JQogIGRwbHlyOjpzZWxlY3QoVGF4b24sIElEKSAlPiUKICBkaXN0aW5jdChJRCwgLmtlZXBfYWxsID0gVFJVRSkKICAKYGBgCgotICAgKioqY2hhbmdlKioqIFRyYWl0IG5hbWU6ICdBZ29zZXJpcycgLS1cPiAnQWdvc2VyaXMgdW5rbm93bic7IGFzc3VtaW5nIHRoZSBzYW1lIGFzICdBR1NQJyAtLVw+ICdBZ29zZXJpcyBzcC4nIGluIG1hdHJpeCBkYXRhIChjaGFuZ2UgdG8gbWF0cml4IG5hbWUpCgotICAgW1doYXQncyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuOl17LnVuZGVybGluZX0KCiAgICAtICAgJ0FOQVInIGFuZCAnQU5BUnAnIGluIHRyYWl0IGRhdGE/CgogICAgLSAgICdCUkhPJyBhbmQgJ0JSSE9wJyBpbiB0cmFpdCBkYXRhPwoKICAgIC0gICAnQlJOSWYnIGFuZCAnQlJOSXAnIGluIHRyYWl0IGRhdGE/IChub3QgaW4gbWF0cml4IGRhdGEpCgogICAgLSAgICdDTFBVZicgYW5kICdDTFBVcCcgaW4gdHJhaXQgZGF0YT8gKG5vdCBpbiBtYXRyaXggZGF0YSkKCiAgICAtICAgJ0dJVFJmJyBhbmQgJ0dJVFJwJyBpbiB0cmFpdCBkYXRhPyAobm90IGluIG1hdHJpeCBkYXRhKQoKICAgIC0gICAnTEVOSWYnIGFuZCAnTEVOSXAnIGluIHRyYWl0IGRhdGE/IChub3QgaW4gbWF0cml4IGRhdGEpCgogICAgLSAgICdUUkhJJyBhbmQgJ1RSSElwaScgKHNhbWUgc3AgbmFtZSkgaW4gdHJhaXQgZGF0YT8gKFRSSEkgaW4gbWF0cml4IGRhdGEpCgogICAgLSAgICdUUldJZicgYW5kICdUUldJcCcgYW5kICdUUldJcGknIGluIHRyYWl0IGRhdGE/IChub3QgaW4gbWF0cml4IGRhdGEpCgogICAgLSAgICdDcmFzc3VsYScgYW5kICdDcmFzc3VsYSB0aWxsYWVhJyAoY291bGQgdGhleSBiZSB0aGUgc2FtZT8pCgogICAgLSAgICdTYW5pY3VsYScgKHVua25vd24pIGFuZCAnU0FCSTEnIG9yICdTQUJJMicgKGNvdWxkIHRoZXkgYmUgdGhlIHNhbWU/KQoKICAgIC0gICAnTUFFTGYnICh0cmFpdCBkYXRhKSBhbmQgJ01BRDEnIChNYWRpYSBzcC4gMSAoInRhbGwgdGFyd2VlZCIpJyAoY291bGQgdGhleSBiZSB0aGUgc2FtZT8pCgogICAgLSAgICdNQUVMcCcgKHRyYWl0IGRhdGEpIGFuZCAnTUFEMicgKE1hZGlhIHNwLiAxICgic21hbGwgdGFyd2VlZCIpJyAoY291bGQgdGhleSBiZSB0aGUgc2FtZT8pCgogICAgLSAgICdUcmlmb2xpdW0gZXJpb2NlcGhhbHVtJyAoVFJFUikgYW5kICdUcmlwaHlzYXJpYSBlcmlhbnRoYScgKFRSRVIpIChjb3VsZCB0aGV5IGJlIHRoZSBzYW1lPykKCi0gICAqKipjaGFuZ2UqKiogJ0FWRUJBUicgKHRyYWl0IGRhdGEpIHRvICdBVkJBJyAobWF0cml4IGRhdGEpCgotICAgKioqY2hhbmdlKioqIEJSRFIgLS1cPiBCUkRJCgojIyBPdmVybGF5IFRyYWl0IFZlY3RvcnMgb250byBOTURTCgojIyMgQUxMIFlFQVJTIC0tIExPVyBBTkQgSElHSCBHUkFaSU5HCgojIyMjIFByZXBhcmUgTk1EUyBhbmQgVHJhaXRzCgpTdHJlc3M6CgpgYGAgICAgICAgICAKMC4yMDExMTI3CmBgYAoKYGBge3J9CiMgc3Vic2V0IG5tZHMgdG8gbWF0Y2ggc3BlY2llcyBuYW1lcwpubWRzLmNvbXAudHJhaXQgPC0gbWV0YU1EUyhtYXRyaXguYnJheSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGludGVyc2VjdC5uYW1lcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBrPTIsIHRyeW1heCA9IDI1KQpubWRzLmNvbXAudHJhaXQgIyBwcmV0dHkgbm90IGdyZWF0IHN0cmVzcwpzdHJlc3NwbG90KG5tZHMuY29tcC50cmFpdCkKcGxvdChubWRzLmNvbXAudHJhaXQsIHR5cGU9InQiKQoKbm1kczEgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy5jb21wLnRyYWl0LCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic3BlY2llcyIpKSkKbm1kczIgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy5jb21wLnRyYWl0LCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic3BlY2llcyIpKSkKCm5tZHNfZGF0X3RyYWl0IDwtIGNiaW5kKG5tZHMxLCBubWRzMikgJT4lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJzcGVjaWVzX2lkIikgJT4lCiAgc2VwYXJhdGUoc3BlY2llc19pZCwgaW50byA9IGMoIklEIiksIHNlcCA9ICJfIikKCgojIHN1YnNldCBtYXRyaXggYW5kIHRyYWl0IGRhdGEgdG8gbWF0Y2ggbmFtZXMKdHJhaXRzLm1lYW5zLmNvbXAgPC0gdHJhaXRzLm1lYW5zICU+JQogIGZpbHRlcihJRCAlaW4lIGludGVyc2VjdC5uYW1lcykgCiMgdHJhaXRzLm1lYW5zLmNvbXAyIDwtIHRyYWl0cy5tZWFucy5jb21wICU+JQogICMgZHBseXI6OnNlbGVjdCgtSUQpCnJvd25hbWVzKHRyYWl0cy5tZWFucy5jb21wMikgPC0gdHJhaXRzLm1lYW5zLmNvbXAkSUQKCiMgdHJhaXQgdmVjdG9ycyBvbnRvIHRoZSBOTURTCmVudmZpdChubWRzLmNvbXAudHJhaXQsIHRyYWl0cy5tZWFucy5jb21wLCBwZXJtdXRhdGlvbnMgPSA5OTkpCmBgYAoKIyMjIyBQbG90IAoKYGBge3J9CmdncGxvdChubWRzX2RhdF90cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0LCBjb2xvciA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBOdXRyaWVudCBUcmVhdG1lbnQiKSArCiAgY3VzdG9tX2NvbG9ycyArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikKCmdncGxvdChubWRzX2RhdF90cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgY29sb3IgPSBhcy5mYWN0b3IoeXIpLCBmaWxsID0gYXMuZmFjdG9yKHlyKSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IFllYXIiKQoKZ2dwbG90KG5tZHNfZGF0X3RyYWl0LCBhZXMoTk1EUzEsIE5NRFMyLCBmaWxsID0gYXMuZmFjdG9yKHBwdF90cnQpLCBjb2xvciA9IGFzLmZhY3RvcihwcHRfdHJ0KSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikgKwogIGN1c3RvbV9jb2xvcnMgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopCgpnZ3Bsb3Qobm1kc19kYXRfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCksIGNvbG9yID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCkpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBHcmF6aW5nIEhpc3RvcnkiKQoKZ2dwbG90KG5tZHNfZGF0X3RyYWl0LCBhZXMoTk1EUzEsIE5NRFMyLCAgY29sb3IgPSBhcy5mYWN0b3IoZ3JhemluZ19oaXN0KSwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiAgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGFzLmZhY3Rvcih5cikpLCBzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMSkgKwogIHN0YXRfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoeXIpKSwgCiAgICAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAogICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IEdyYXppbmcgSGlzdG9yeSAmIFllYXIiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAibG93IiA9ICJjeWFuIiwKICAgICJoaWdoIiA9ICJicm93biIsCiAgIjIwMTkiID0gInNhbG1vbiIsCiAgIjIwMjAiID0gImxpbWVncmVlbiIsCiAgIjIwMjEiID0gImNvcm5mbG93ZXJibHVlIikKICApCiAgCmdncGxvdChubWRzX2RhdF90cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgY29sb3IgPSBudXRfdHJ0LCBmaWxsID0gYXMuZmFjdG9yKHlyKSkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAxKSArCiAgc3RhdF9lbGxpcHNlKGFlcyhjb2xvciA9IGFzLmZhY3RvcihudXRfdHJ0KSksCiAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAogICAgICAgICAgICAgZmlsbCA9IE5BLCAgIyBNYWtlcyB0aGUgZWxsaXBzZSB0cmFuc3BhcmVudCBpbnNpZGUKICAgICAgICAgICAgIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IE51dHJpZW50IFRyZWF0bWVudCAmIFllYXIiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikKYGBgCgpgYGB7cn0KIyBzZXRkaWZmKGNvbG5hbWVzKG1hdHJpeC5icmF5KSwgdHJhaXRzLmdoLm1lYW5zJElEKQojIHNldGRpZmYodHJhaXRzLmdoLm1lYW5zJElELCBjb2xuYW1lcyhtYXRyaXguYnJheSkpCnRyYWl0cy5naC5tZWFuczIgPC0gdHJhaXRzLmdoLm1lYW5zICU+JQogIGZpbHRlcihJRCAlaW4lIGludGVyc2VjdChjb2xuYW1lcyhtYXRyaXguYnJheSksIHRyYWl0cy5naC5tZWFucyRJRCkpCnJvd25hbWVzKHRyYWl0cy5naC5tZWFuczIpIDwtIGFzLmNoYXJhY3Rlcih0cmFpdHMuZ2gubWVhbnMyJElEKQoKbWF0cml4LmJyYXkgJT4lCiAgc2VsZWN0KGFsbF9vZihpbnRlcnNlY3QoY29sbmFtZXMobWF0cml4LmJyYXkpLCB0cmFpdHMuZ2gubWVhbnMkSUQpKSkgIyBpcyB0aGlzIGFwcHJvcHJpYXRlPyBzaG91bGQgaSByZWxhdGl2aXplIGl0IGFsbCBvbmx5IHdpdGggdGhlc2Ugc3BlY2llcyBpbnN0ZWFkIG9mIGp1c3QgY3V0dGluZyBvdXQgc3BlY2llcz8Kbm1kcy5jb21wLjIgPC0gbWV0YU1EUyhtYXRyaXguYnJheSAlPiUKICBzZWxlY3QoYWxsX29mKGludGVyc2VjdChjb2xuYW1lcyhtYXRyaXguYnJheSksIHRyYWl0cy5naC5tZWFucyRJRCkpKSwgaz0yLCB0cnltYXggPSAyNSkKbm1kcy5jb21wLjIgIyBwcmV0dHkgbm90IGdyZWF0IHN0cmVzcwpzdHJlc3NwbG90KG5tZHMuY29tcC4yKQpwbG90KG5tZHMuY29tcC4yLCB0eXBlPSJ0IikKCmVudmZpdChubWRzLmNvbXAuMiwgdHJhaXRzLmdoLm1lYW5zMiwgcGVybXV0YXRpb25zID0gOTk5KQoKCgpgYGAK